| Dimension | Shared | Only in A | Only in B | Overlap |
|---|---|---|---|---|
| Sections | 2 | 6 | 6 | 14% |
| Commands | 4 | 1 | 14 | 21% |
| Section tags | 4 | 1 | 2 | 57% |
What each file covers
Sections
2 shared · 6 only in A · 6 only in B- − Gemini Code Assistant Guide for Hovimestari
- − Core Architecture & Key Files
- − Developer Workflow & Commands
- − Import calendar events
- − Generate the daily brief
- − Project Conventions
- + CLAUDE.md
- + Development Workflow
- + Architecture
- + Configuration
- + Memory System
- + Development Guidelines
- Project Overview
- Testing
Commands
4 shared · 1 only in A · 14 only in B- − go.mod
- + task build-linux
- + task import-calendar
- + task import-weather
- + task import-water-quality
- + task generate-brief
- + task add-memory CONTENT="text" RELEVANCE_DATE="2025-01-01" SOURCE="manual"
- + task init-config
- + task run
- + task publish
- + task upgrade-deps
- + task clean
- + task clean-build
- + task clean-linux
- + go test ./...
- task build
- task test
- task lint
- task deps
Section tags
4 shared · 1 only in A · 2 only in B- − testing-strategy
- + build
- + performance
- test
- code-style
- architecture
- agent-behaviour
Line diff
lepinkainen/hovimestari · GEMINI.md
@@ −1 @@
1# Gemini Code Assistant Guide for Hovimestari
2
3This guide provides essential information for AI code assistants working on the Hovimestari project.
4
5## Project Overview
6
7Hovimestari is a personal AI butler assistant written in Go. It gathers information from various sources (calendars, weather APIs, manual input), stores them as "memories" in a SQLite database, and uses a Large Language Model (LLM) to generate a personalized daily brief.
8
9- **Inspiration**: [Geoffrey Litt's AI assistant](https://www.geoffreylitt.com/2025/04/12/how-i-made-a-useful-ai-assistant-with-one-sqlite-table-and-a-handful-of-cron-jobs)
10- **Name**: "Hovimestari" is Finnish for "Butler".
11- **Primary Language**: Briefs are generated in Finnish by default, but the codebase, comments, and logs are in English.
12
13## Core Architecture & Key Files
14
15The project follows a modular structure, separating concerns into distinct packages within the `internal/` directory.
16
17- **Entry Point**: `cmd/hovimestari/main.go` initializes the [Cobra](https://github.com/spf13/cobra) CLI.
18- **CLI Commands**: Each command is a separate file in `cmd/hovimestari/commands/`.
19- **Configuration**: `internal/config/viper.go` manages configuration using [Viper](https://github.com/spf13/viper), supporting file-based (`config.json`), environment variables, and XDG standard directories (`~/.config/hovimestari/`).
20- **Database**: `internal/store/store.go` handles all interactions with the SQLite database (`memories.db`). It uses `modernc.org/sqlite` for CGO-free compilation. All data is stored in a single `memories` table.
21- **Brief Generation**: `internal/brief/brief.go` orchestrates the collection of memories and context to generate the final brief via the LLM.
22- **LLM Interaction**: `internal/llm/gemini.go` contains the client for the Google Gemini API. Prompts are stored in `prompts.json`.
23- **Importers**: Data sources are implemented as importers in `internal/importer/`. For example, `internal/importer/calendar/calendar.go` handles iCalendar/WebCal imports.
24- **Output**: `internal/output/` contains a multi-destination system to send briefs to the CLI, Discord, and Telegram.
25
26## Developer Workflow & Commands
27
28This project uses [Task](https://taskfile.dev/) as a command runner instead of Make. All common development tasks are defined in `Taskfile.yml`.
29
30- **Build the application**:
31
32 ```bash
33 task build
34 ```
35
36- **Run all tests**:
37
38 ```bash
39 task test
40 ```
41
42- **Run linter**:
43
44 ```bash
45 task lint
46 ```
47
48- **Tidy dependencies**:
49
50 ```bash
51 task deps
52 ```
53
54Application commands are executed via the compiled binary. For example:
55
56```bash
57# Import calendar events
58./build/hovimestari import-calendar
59
60# Generate the daily brief
61./build/hovimestari generate-brief
62```
63
64## Project Conventions
65
66- **Error Handling**: Use the `fmt.Errorf("...: %w", err)` pattern to wrap and add context to errors.
67- **Logging**: The project uses the standard `log/slog` library with a custom human-readable handler in `internal/logging/handler.go`. Use this for all logging.
68- **Dependencies**: Use the standard library where possible. For external dependencies, ensure they are added to `go.mod` and run `task deps`.
69- **Configuration**: When adding new configuration options, update the `Config` struct in `internal/config/viper.go` and the `config.example.json` file.
70- **Adding a Command**: To add a new CLI command, create a new file in `cmd/hovimestari/commands/` and add it to the root command in `cmd/hovimestari/main.go`. Follow the existing Cobra command structure.
71
72## Testing
73
74- Tests are located in `*_test.go` files alongside the code they test.
75- Tests should be deterministic and not rely on external services (network, LLM APIs, or the database). Mock these dependencies where necessary.
76- Run all tests using `task test`.
77
lepinkainen/hovimestari · CLAUDE.md
@@ +1 @@
1# CLAUDE.md
2
3This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
5## Project Overview
6
7Hovimestari ("Butler" in Finnish) is a Go-based personal AI butler assistant inspired by Geoffrey Litt's Stevens assistant. It stores "memories" in a single SQLite table, imports data from multiple sources (calendars, weather, manual input), and generates personalized daily briefs using Google Gemini API. The project emphasizes simplicity with a pure Go implementation for easy cross-compilation.
8
9## Development Workflow
10
11**Build System**: Uses [Task](https://taskfile.dev/) runner instead of Make (see `Taskfile.yml`). Build depends on lint and test passing.
12
13**Critical Commands**:
14
15- `task build` - Build for current OS/ARCH (runs lint + test first)
16- `task build-linux` - Cross-compile for Linux AMD64 (CGO-free)
17- `task test` - Run all tests (deterministic, no external deps)
18- `task lint` - Run golangci-lint (required before commit)
19- `task deps` - Tidy Go module dependencies
20
21**Application Commands**:
22
23- `task import-calendar` - Import WebCal/iCalendar events with smart/full_refresh modes
24- `task import-weather` - Import MET Norway weather forecasts
25- `task import-water-quality` - Import water quality data for specific locations
26- `task generate-brief` - Generate daily brief using LLM and current memories
27- `task add-memory CONTENT="text" RELEVANCE_DATE="2025-01-01" SOURCE="manual"` - Add manual memory
28- `task init-config` - Initialize config (reads GEMINI_API_KEY, WEBCAL_URL from env)
29- `task run` - Build and run the application
30- `task publish` - Deploy binary to remote server
31
32**Utility Commands**:
33
34- `task upgrade-deps` - Upgrade all Go dependencies
35- `task clean` - Clean all build artifacts
36- `task clean-build` - Clean build directory only
37- `task clean-linux` - Clean Linux build artifacts
38
39**Direct CLI Usage**: `./build/hovimestari <command> --config=/path/to/config.json --log-level=debug`
40
41**Available CLI Commands**:
42
43- `import-calendar` - Import calendar events from WebCal/iCalendar URLs
44- `import-weather` - Import weather forecasts from MET Norway
45- `import-water-quality` - Import water quality data
46- `generate-brief` - Generate personalized daily brief
47- `show-brief-context` - Show context that would be sent to LLM without generating brief (debug)
48- `add-memory` - Add manual memory entry
49- `init-config` - Initialize configuration file
50- `list-models` - List available Gemini LLM models
51
52## Architecture
53
54**CLI Framework**: Uses `alecthomas/kong` (not Cobra) for command parsing in `cmd/hovimestari/main.go`. Global flags: `--config`, `--log-level`
55
56**Core Data Flow**:
57
581. **Import Phase**: Various importers fetch data → format as memories → store in SQLite
592. **Brief Generation**: `internal/brief/brief.go` queries relevant memories → combines with prompts → sends to LLM → outputs to multiple destinations
60
61**Key Components**:
62
63- `internal/store/store.go` - Two SQLite tables (`memories` and `calendar_events`) with source-based organization
64- `internal/config/viper.go` - Viper configuration with XDG Base Directory support
65- `internal/brief/brief.go` - Brief generation orchestrator combining memories + LLM
66- `internal/llm/gemini.go` - Google Gemini API client (supports multiple models)
67- `internal/logging/handler.go` - Custom slog handler for human-readable output
68- `internal/output/` - Multi-destination system (CLI, Discord, Telegram)
69
70**Importers Pattern**:
71
72- `internal/importer/calendar/` - WebCal imports with smart (upsert) vs full_refresh (replace_all) strategies
73- `internal/importer/weather/` - MET Norway API integration
74- Commands in `cmd/hovimestari/commands/` for manual data entry
75
76**Design Principles**:
77
78- **Two-Table Design**:
79 - `memories` table for general memories (weather, manual entries, etc.) with hierarchical `source` field (e.g., "weather:helsinki", "manual")
80 - `calendar_events` table for structured calendar data with proper datetime columns
81- **Pure Go**: Uses `modernc.org/sqlite` (no CGO) for cross-compilation without Docker
82- **XDG Compliance**: Config files follow standard (`~/.config/hovimestari/`)
83- **Extensible I/O**: Output system supports multiple simultaneous destinations
84
85## Configuration
86
87**Files**: `config.json`, `prompts.json`, `memories.db` (SQLite)
88
89**Config Resolution Order**:
90
911. `--config` flag path
922. `$XDG_CONFIG_HOME/hovimestari/` (usually `~/.config/hovimestari/`)
933. Directory containing executable
94
95**Key Config Fields**:
96
97- `gemini_api_key`, `gemini_model` - LLM configuration
98- `calendars[]` with `update_mode: "smart"|"full_refresh"` - Calendar import strategy
99- `outputs.enable_cli`, `outputs.discord_webhook_urls[]`, `outputs.telegram_bots[]` - Multi-destination output
100- `family[]` with optional birthdays - Birthday tracking in briefs
101
102## Memory System
103
104Data is stored in two SQLite tables:
105
106**1. `memories` table** - For general memories (weather, manual entries):
107
108- `content` - Formatted text (e.g., "Weather: Sunny, 20°C in Helsinki")
109- `source` - Hierarchical source identifier (e.g., "weather:helsinki", "manual")
110- `relevance_date` - When memory is relevant (used for brief filtering)
111- `uid` - Optional unique identifier for deduplication
112
113**2. `calendar_events` table** - For structured calendar data:
114
115- `uid` - Unique event identifier (prevents duplicates)
116- `summary` - Event title/summary
117- `start_time`, `end_time` - Event datetime range
118- `location` - Event location (optional)
119- `description` - Event description (optional)
120- `source` - Hierarchical source identifier (e.g., "calendar:work", "calendar:personal")
121- `created_at` - When the event was imported
122
123## Testing
124
125Tests exist for deterministic functions in `*_test.go` files:
126
127- Calendar URL conversion and event formatting
128- Weather forecast formatting
129- Output system behavior
130
131Run with `task test` or `go test ./...`. Tests avoid external dependencies (network, database, LLM calls).
132
133## Development Guidelines
134
135**Code Style**: Follow `.clinerules/go-codestyle.md` conventions:
136
137- Use `fmt.Errorf("failed to X: %w", err)` for error wrapping
138- Prefer standard library, use `alecthomas/kong` for CLI, `spf13/viper` for config
139- Use `modernc.org/sqlite` for SQLite (CGO-free)
140- Use `slog` for logging, `fmt.Printf` for interactive output
141
142**Testing Strategy**:
143
144- Tests avoid external dependencies (network, database, LLM calls)
145- Focus on deterministic functions: URL conversion, data formatting, parsing
146- Examples: `calendar_test.go` (event formatting), `weather_test.go` (forecast formatting)
147- Run `task test` (includes in build pipeline)
148
149**Adding New Features**:
150
151- **New Importer**: Create package in `internal/importer/`, implement similar interface to calendar importer
152- **New Command**: Add file in `cmd/hovimestari/commands/`, follow Kong CLI pattern
153- **New Config**: Update `Config` struct in `internal/config/viper.go`, add to `config.example.json`
154
155**Memory Storage Pattern**:
156
157```go
158// Pattern 1: General memories (weather, manual entries)
159content := fmt.Sprintf("Weather: %s, %.1f°C in %s", condition, temp, location)
160source := "weather:" + locationName // Hierarchical source naming
161uid := "" // Optional unique identifier for deduplication
162// Store in memories table
163
164// Pattern 2: Calendar events (stored in dedicated table)
165calendarEvent := CalendarEvent{
166 UID: event.UID,
167 Summary: event.Summary,
168 StartTime: event.Start,
169 EndTime: event.End,
170 Location: event.Location,
171 Description: event.Description,
172 Source: "calendar:" + calendarName, // Hierarchical source naming
173}
174// Store in calendar_events table
175```
176
177**Cross-Compilation**: Pure Go implementation enables simple `GOOS=linux GOARCH=amd64 go build` without Docker or CGO
178
179**Commit Requirements**: Always run `task build` (includes lint + test) before commits
180
@@ −1 +1 @@
1−# Gemini Code Assistant Guide for Hovimestari
1+# CLAUDE.md
22
3−This guide provides essential information for AI code assistants working on the Hovimestari project.
3+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
44
55 ## Project Overview
66
7−Hovimestari is a personal AI butler assistant written in Go. It gathers information from various sources (calendars, weather APIs, manual input), stores them as "memories" in a SQLite database, and uses a Large Language Model (LLM) to generate a personalized daily brief.
7+Hovimestari ("Butler" in Finnish) is a Go-based personal AI butler assistant inspired by Geoffrey Litt's Stevens assistant. It stores "memories" in a single SQLite table, imports data from multiple sources (calendars, weather, manual input), and generates personalized daily briefs using Google Gemini API. The project emphasizes simplicity with a pure Go implementation for easy cross-compilation.
88
9−- **Inspiration**: [Geoffrey Litt's AI assistant](https://www.geoffreylitt.com/2025/04/12/how-i-made-a-useful-ai-assistant-with-one-sqlite-table-and-a-handful-of-cron-jobs)
10−- **Name**: "Hovimestari" is Finnish for "Butler".
11−- **Primary Language**: Briefs are generated in Finnish by default, but the codebase, comments, and logs are in English.
9+## Development Workflow
1210
13−## Core Architecture & Key Files
11+**Build System**: Uses [Task](https://taskfile.dev/) runner instead of Make (see `Taskfile.yml`). Build depends on lint and test passing.
1412
15−The project follows a modular structure, separating concerns into distinct packages within the `internal/` directory.
13+**Critical Commands**:
1614
17−- **Entry Point**: `cmd/hovimestari/main.go` initializes the [Cobra](https://github.com/spf13/cobra) CLI.
18−- **CLI Commands**: Each command is a separate file in `cmd/hovimestari/commands/`.
19−- **Configuration**: `internal/config/viper.go` manages configuration using [Viper](https://github.com/spf13/viper), supporting file-based (`config.json`), environment variables, and XDG standard directories (`~/.config/hovimestari/`).
20−- **Database**: `internal/store/store.go` handles all interactions with the SQLite database (`memories.db`). It uses `modernc.org/sqlite` for CGO-free compilation. All data is stored in a single `memories` table.
21−- **Brief Generation**: `internal/brief/brief.go` orchestrates the collection of memories and context to generate the final brief via the LLM.
22−- **LLM Interaction**: `internal/llm/gemini.go` contains the client for the Google Gemini API. Prompts are stored in `prompts.json`.
23−- **Importers**: Data sources are implemented as importers in `internal/importer/`. For example, `internal/importer/calendar/calendar.go` handles iCalendar/WebCal imports.
24−- **Output**: `internal/output/` contains a multi-destination system to send briefs to the CLI, Discord, and Telegram.
15+- `task build` - Build for current OS/ARCH (runs lint + test first)
16+- `task build-linux` - Cross-compile for Linux AMD64 (CGO-free)
17+- `task test` - Run all tests (deterministic, no external deps)
18+- `task lint` - Run golangci-lint (required before commit)
19+- `task deps` - Tidy Go module dependencies
2520
26−## Developer Workflow & Commands
21+**Application Commands**:
2722
28−This project uses [Task](https://taskfile.dev/) as a command runner instead of Make. All common development tasks are defined in `Taskfile.yml`.
23+- `task import-calendar` - Import WebCal/iCalendar events with smart/full_refresh modes
24+- `task import-weather` - Import MET Norway weather forecasts
25+- `task import-water-quality` - Import water quality data for specific locations
26+- `task generate-brief` - Generate daily brief using LLM and current memories
27+- `task add-memory CONTENT="text" RELEVANCE_DATE="2025-01-01" SOURCE="manual"` - Add manual memory
28+- `task init-config` - Initialize config (reads GEMINI_API_KEY, WEBCAL_URL from env)
29+- `task run` - Build and run the application
30+- `task publish` - Deploy binary to remote server
2931
30−- **Build the application**:
32+**Utility Commands**:
3133
32− ```bash
33− task build
34− ```
34+- `task upgrade-deps` - Upgrade all Go dependencies
35+- `task clean` - Clean all build artifacts
36+- `task clean-build` - Clean build directory only
37+- `task clean-linux` - Clean Linux build artifacts
3538
36−- **Run all tests**:
39+**Direct CLI Usage**: `./build/hovimestari <command> --config=/path/to/config.json --log-level=debug`
3740
38− ```bash
39− task test
40− ```
41+**Available CLI Commands**:
4142
42−- **Run linter**:
43+- `import-calendar` - Import calendar events from WebCal/iCalendar URLs
44+- `import-weather` - Import weather forecasts from MET Norway
45+- `import-water-quality` - Import water quality data
46+- `generate-brief` - Generate personalized daily brief
47+- `show-brief-context` - Show context that would be sent to LLM without generating brief (debug)
48+- `add-memory` - Add manual memory entry
49+- `init-config` - Initialize configuration file
50+- `list-models` - List available Gemini LLM models
4351
44− ```bash
45− task lint
46− ```
52+## Architecture
4753
48−- **Tidy dependencies**:
54+**CLI Framework**: Uses `alecthomas/kong` (not Cobra) for command parsing in `cmd/hovimestari/main.go`. Global flags: `--config`, `--log-level`
4955
50− ```bash
51− task deps
52− ```
56+**Core Data Flow**:
5357
54−Application commands are executed via the compiled binary. For example:
58+1. **Import Phase**: Various importers fetch data → format as memories → store in SQLite
59+2. **Brief Generation**: `internal/brief/brief.go` queries relevant memories → combines with prompts → sends to LLM → outputs to multiple destinations
5560
56−```bash
57−# Import calendar events
58−./build/hovimestari import-calendar
61+**Key Components**:
5962
60−# Generate the daily brief
61−./build/hovimestari generate-brief
62−```
63+- `internal/store/store.go` - Two SQLite tables (`memories` and `calendar_events`) with source-based organization
64+- `internal/config/viper.go` - Viper configuration with XDG Base Directory support
65+- `internal/brief/brief.go` - Brief generation orchestrator combining memories + LLM
66+- `internal/llm/gemini.go` - Google Gemini API client (supports multiple models)
67+- `internal/logging/handler.go` - Custom slog handler for human-readable output
68+- `internal/output/` - Multi-destination system (CLI, Discord, Telegram)
6369
64−## Project Conventions
70+**Importers Pattern**:
6571
66−- **Error Handling**: Use the `fmt.Errorf("...: %w", err)` pattern to wrap and add context to errors.
67−- **Logging**: The project uses the standard `log/slog` library with a custom human-readable handler in `internal/logging/handler.go`. Use this for all logging.
68−- **Dependencies**: Use the standard library where possible. For external dependencies, ensure they are added to `go.mod` and run `task deps`.
69−- **Configuration**: When adding new configuration options, update the `Config` struct in `internal/config/viper.go` and the `config.example.json` file.
70−- **Adding a Command**: To add a new CLI command, create a new file in `cmd/hovimestari/commands/` and add it to the root command in `cmd/hovimestari/main.go`. Follow the existing Cobra command structure.
72+- `internal/importer/calendar/` - WebCal imports with smart (upsert) vs full_refresh (replace_all) strategies
73+- `internal/importer/weather/` - MET Norway API integration
74+- Commands in `cmd/hovimestari/commands/` for manual data entry
7175
76+**Design Principles**:
77+
78+- **Two-Table Design**:
79+ - `memories` table for general memories (weather, manual entries, etc.) with hierarchical `source` field (e.g., "weather:helsinki", "manual")
80+ - `calendar_events` table for structured calendar data with proper datetime columns
81+- **Pure Go**: Uses `modernc.org/sqlite` (no CGO) for cross-compilation without Docker
82+- **XDG Compliance**: Config files follow standard (`~/.config/hovimestari/`)
83+- **Extensible I/O**: Output system supports multiple simultaneous destinations
84+
85+## Configuration
86+
87+**Files**: `config.json`, `prompts.json`, `memories.db` (SQLite)
88+
89+**Config Resolution Order**:
90+
91+1. `--config` flag path
92+2. `$XDG_CONFIG_HOME/hovimestari/` (usually `~/.config/hovimestari/`)
93+3. Directory containing executable
94+
95+**Key Config Fields**:
96+
97+- `gemini_api_key`, `gemini_model` - LLM configuration
98+- `calendars[]` with `update_mode: "smart"|"full_refresh"` - Calendar import strategy
99+- `outputs.enable_cli`, `outputs.discord_webhook_urls[]`, `outputs.telegram_bots[]` - Multi-destination output
100+- `family[]` with optional birthdays - Birthday tracking in briefs
101+
102+## Memory System
103+
104+Data is stored in two SQLite tables:
105+
106+**1. `memories` table** - For general memories (weather, manual entries):
107+
108+- `content` - Formatted text (e.g., "Weather: Sunny, 20°C in Helsinki")
109+- `source` - Hierarchical source identifier (e.g., "weather:helsinki", "manual")
110+- `relevance_date` - When memory is relevant (used for brief filtering)
111+- `uid` - Optional unique identifier for deduplication
112+
113+**2. `calendar_events` table** - For structured calendar data:
114+
115+- `uid` - Unique event identifier (prevents duplicates)
116+- `summary` - Event title/summary
117+- `start_time`, `end_time` - Event datetime range
118+- `location` - Event location (optional)
119+- `description` - Event description (optional)
120+- `source` - Hierarchical source identifier (e.g., "calendar:work", "calendar:personal")
121+- `created_at` - When the event was imported
122+
72123 ## Testing
73124
74−- Tests are located in `*_test.go` files alongside the code they test.
75−- Tests should be deterministic and not rely on external services (network, LLM APIs, or the database). Mock these dependencies where necessary.
76−- Run all tests using `task test`.
125+Tests exist for deterministic functions in `*_test.go` files:
126+
127+- Calendar URL conversion and event formatting
128+- Weather forecast formatting
129+- Output system behavior
130+
131+Run with `task test` or `go test ./...`. Tests avoid external dependencies (network, database, LLM calls).
132+
133+## Development Guidelines
134+
135+**Code Style**: Follow `.clinerules/go-codestyle.md` conventions:
136+
137+- Use `fmt.Errorf("failed to X: %w", err)` for error wrapping
138+- Prefer standard library, use `alecthomas/kong` for CLI, `spf13/viper` for config
139+- Use `modernc.org/sqlite` for SQLite (CGO-free)
140+- Use `slog` for logging, `fmt.Printf` for interactive output
141+
142+**Testing Strategy**:
143+
144+- Tests avoid external dependencies (network, database, LLM calls)
145+- Focus on deterministic functions: URL conversion, data formatting, parsing
146+- Examples: `calendar_test.go` (event formatting), `weather_test.go` (forecast formatting)
147+- Run `task test` (includes in build pipeline)
148+
149+**Adding New Features**:
150+
151+- **New Importer**: Create package in `internal/importer/`, implement similar interface to calendar importer
152+- **New Command**: Add file in `cmd/hovimestari/commands/`, follow Kong CLI pattern
153+- **New Config**: Update `Config` struct in `internal/config/viper.go`, add to `config.example.json`
154+
155+**Memory Storage Pattern**:
156+
157+```go
158+// Pattern 1: General memories (weather, manual entries)
159+content := fmt.Sprintf("Weather: %s, %.1f°C in %s", condition, temp, location)
160+source := "weather:" + locationName // Hierarchical source naming
161+uid := "" // Optional unique identifier for deduplication
162+// Store in memories table
163+
164+// Pattern 2: Calendar events (stored in dedicated table)
165+calendarEvent := CalendarEvent{
166+ UID: event.UID,
167+ Summary: event.Summary,
168+ StartTime: event.Start,
169+ EndTime: event.End,
170+ Location: event.Location,
171+ Description: event.Description,
172+ Source: "calendar:" + calendarName, // Hierarchical source naming
173+}
174+// Store in calendar_events table
175+```
176+
177+**Cross-Compilation**: Pure Go implementation enables simple `GOOS=linux GOARCH=amd64 go build` without Docker or CGO
178+
179+**Commit Requirements**: Always run `task build` (includes lint + test) before commits
77180
