Two files, one repository
lepinkainen/hovimestari ships 4 formats across 5 indexed files. The question worth asking is whether the second one says anything the first does not.
| Dimension | Shared | Only in A | Only in B | Overlap |
|---|---|---|---|---|
| Sections | 0 | 7 | 8 | 0% |
| Commands | 4 | 6 | 14 | 17% |
| Section tags | 4 | 4 | 2 | 40% |
What each file covers
Sections
0 shared · 7 only in A · 8 only in B- − Repository Guidelines
- − Project Structure & Module Organization
- − Build, Test, and Development Commands
- − Coding Style & Naming Conventions
- − Testing Guidelines
- − Commit & Pull Request Guidelines
- − Configuration & Secrets
- + CLAUDE.md
- + Project Overview
- + Development Workflow
- + Architecture
- + Configuration
- + Memory System
- + Testing
- + Development Guidelines
Commands
4 shared · 6 only in A · 14 only in B- − task run -- generate-brief
- − go build ./cmd/hovimestari
- − go test ./internal/...
- − go test -cover ./...
- − git log
- − task
- + task build-linux
- + task deps
- + 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
- task build
- task test
- go test ./...
- task lint
Section tags
4 shared · 4 only in A · 2 only in B- − lint-format
- − git-pr
- − security
- − do-not
- + performance
- + agent-behaviour
- build
- test
- code-style
- architecture
Line diff
lepinkainen/hovimestari · AGENTS.md
@@ −1 @@
1# Repository Guidelines
2
3## Project Structure & Module Organization
4- Entry point lives in `cmd/hovimestari`, wiring the CLI with Kong.
5- Domain logic sits under `internal/*`: `brief` assembles daily briefs, `importer` handles calendar/weather ingestion, `store` wraps SQLite access, and `output` manages delivery channels.
6- Shared prompt artifacts reside in `llm-shared/`; background documentation sits in `docs/`.
7- Tests stay alongside sources as `_test.go` files; builds land in `build/`, and `config.example.json` documents configurable fields.
8
9## Build, Test, and Development Commands
10- `task build` runs lint and tests before emitting `build/hovimestari`.
11- `task run -- generate-brief` rebuilds then invokes the binary; append any CLI subcommand after `--`.
12- `task test` wraps `go test ./...`; add flags like `-race` or `-run` when needed.
13- `task lint` requires `golangci-lint` in `PATH`; install via `brew install golangci-lint` or the official script.
14- For quick iteration use `go build ./cmd/hovimestari` or `go test ./internal/...` directly.
15
16## Coding Style & Naming Conventions
17- Always format with `gofmt` (or `goimports`); Task targets assume formatted code.
18- Keep package names aligned with directory names (e.g., `internal/weather`, `internal/output`).
19- Exported symbols use CamelCase plus short doc comments; file-level helpers stay lowerCamelCase.
20- Configuration structs belong in `internal/config`; JSON keys mirror `config.example.json` using lower_case.
21
22## Testing Guidelines
23- Use Go's `testing` package with table-driven cases and `_test.go` suffixes.
24- Stub external services by faking interfaces in `internal/llm` or `internal/importer`; avoid live API calls.
25- Run `task test` (or `go test ./...`) before pushing; for coverage snapshots, run `go test -cover ./...`.
26
27## Commit & Pull Request Guidelines
28- Follow Conventional Commits (`feat:`, `fix:`, `chore:`) as in `git log`; keep subjects imperative under ~72 chars.
29- Group related changes per commit and document breaking changes in the body if applicable.
30- PRs should summarize behavior changes, list validation commands, and link issues (`Fixes #12`).
31- Attach CLI transcripts or config snippets when altering user workflows or outputs.
32
33## Configuration & Secrets
34- Use `config.example.json` as the starting point; do not commit populated `config.json`, `.env`, or `memories.db`.
35- Secrets load from `.env`, `$HOME/.hovimestari.env`, or environment variables before running `task` targets.
36- Document new configuration flags in `docs/04_configuration.md` and update sample values in `config.example.json`.
37
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−# Repository Guidelines
1+# CLAUDE.md
22
3−## Project Structure & Module Organization
4−- Entry point lives in `cmd/hovimestari`, wiring the CLI with Kong.
5−- Domain logic sits under `internal/*`: `brief` assembles daily briefs, `importer` handles calendar/weather ingestion, `store` wraps SQLite access, and `output` manages delivery channels.
6−- Shared prompt artifacts reside in `llm-shared/`; background documentation sits in `docs/`.
7−- Tests stay alongside sources as `_test.go` files; builds land in `build/`, and `config.example.json` documents configurable fields.
3+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
84
9−## Build, Test, and Development Commands
10−- `task build` runs lint and tests before emitting `build/hovimestari`.
11−- `task run -- generate-brief` rebuilds then invokes the binary; append any CLI subcommand after `--`.
12−- `task test` wraps `go test ./...`; add flags like `-race` or `-run` when needed.
13−- `task lint` requires `golangci-lint` in `PATH`; install via `brew install golangci-lint` or the official script.
14−- For quick iteration use `go build ./cmd/hovimestari` or `go test ./internal/...` directly.
5+## Project Overview
156
16−## Coding Style & Naming Conventions
17−- Always format with `gofmt` (or `goimports`); Task targets assume formatted code.
18−- Keep package names aligned with directory names (e.g., `internal/weather`, `internal/output`).
19−- Exported symbols use CamelCase plus short doc comments; file-level helpers stay lowerCamelCase.
20−- Configuration structs belong in `internal/config`; JSON keys mirror `config.example.json` using lower_case.
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.
218
22−## Testing Guidelines
23−- Use Go's `testing` package with table-driven cases and `_test.go` suffixes.
24−- Stub external services by faking interfaces in `internal/llm` or `internal/importer`; avoid live API calls.
25−- Run `task test` (or `go test ./...`) before pushing; for coverage snapshots, run `go test -cover ./...`.
9+## Development Workflow
2610
27−## Commit & Pull Request Guidelines
28−- Follow Conventional Commits (`feat:`, `fix:`, `chore:`) as in `git log`; keep subjects imperative under ~72 chars.
29−- Group related changes per commit and document breaking changes in the body if applicable.
30−- PRs should summarize behavior changes, list validation commands, and link issues (`Fixes #12`).
31−- Attach CLI transcripts or config snippets when altering user workflows or outputs.
11+**Build System**: Uses [Task](https://taskfile.dev/) runner instead of Make (see `Taskfile.yml`). Build depends on lint and test passing.
3212
33−## Configuration & Secrets
34−- Use `config.example.json` as the starting point; do not commit populated `config.json`, `.env`, or `memories.db`.
35−- Secrets load from `.env`, `$HOME/.hovimestari.env`, or environment variables before running `task` targets.
36−- Document new configuration flags in `docs/04_configuration.md` and update sample values in `config.example.json`.
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+
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
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+
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+
123+## Testing
124+
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
37180
