Files
agent-tools/notifyr/notify/config.go
claude 9339aac5cf notifyr: ntfy send/read client for agents
send (title/priority/tags), read (poll mode, greppable one-liners),
topics (known homelab buses from config). Config with homelab defaults
on first run. Unit tests against httptest; smoked against the real
ntfy on topic agent-tools-test. Spec: doc/tool-parity.md 3.3.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011KikHkfCiC3yELbsMN8fT9
2026-08-07 00:30:12 +02:00

79 lines
2.1 KiB
Go

package notify
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
)
// Config is ~/.config/notifyr/config.json, created with homelab
// defaults on first run. NOTIFYR_CONFIG overrides the path.
type Config struct {
Server string `json:"server"`
Token string `json:"token"`
DefaultTopic string `json:"default_topic"`
Topics map[string]string `json:"topics"` // known topics -> what they carry (informational)
}
func DefaultConfig() *Config {
return &Config{
Server: "https://ntfy.brasse-pc.eu",
Token: "",
DefaultTopic: "claude",
Topics: map[string]string{
"claude": "agents' direct notes to Björn",
"agent-helm": "agent-helm events (question waiting, session died)",
"Info": "*arr system events",
"media-hamtningar": "media grabbed for download",
"media-nytt": "new media landed in Jellyfin",
"pi5-server": "server maintenance (reboots, watchtower)",
"pi5-server-fel": "server problems: failed units, disk space",
"ci-fel": "failed Gitea Actions builds",
"monitoring": "Uptime Kuma up/down alerts",
},
}
}
func ConfigPath() string {
if p := os.Getenv("NOTIFYR_CONFIG"); p != "" {
return p
}
dir, err := os.UserConfigDir()
if err != nil {
dir = "."
}
return filepath.Join(dir, "notifyr", "config.json")
}
// LoadConfig reads the config, creating it with defaults on first run.
func LoadConfig(path string) (*Config, error) {
cfg := DefaultConfig()
data, err := os.ReadFile(path)
if os.IsNotExist(err) {
if err := SaveConfig(path, cfg); err != nil {
return nil, err
}
fmt.Fprintf(os.Stderr, "notifyr: created %s\n", path)
return cfg, nil
}
if err != nil {
return nil, err
}
if err := json.Unmarshal(data, cfg); err != nil {
return nil, fmt.Errorf("%s: %w", path, err)
}
return cfg, nil
}
func SaveConfig(path string, cfg *Config) error {
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
return err
}
data, err := json.MarshalIndent(cfg, "", " ")
if err != nil {
return err
}
return os.WriteFile(path, append(data, '\n'), 0o600)
}