Files
unpoller-unpoller-4/AGENTS.md
brngates98 969445fade Add AI context files for major LLMs
- Add .cursorrules for Cursor AI
- Add CLAUDE.md for Claude Code
- Add AGENTS.md for universal AI agent context
- Add .github/copilot-instructions.md for GitHub Copilot

These files provide comprehensive context about the UnPoller project
architecture, coding standards, and development patterns to help AI
coding assistants understand and work with the codebase effectively.
2026-01-27 20:40:02 -05:00

7.8 KiB

UnPoller - AI Agent Context

This file provides comprehensive context for AI coding assistants working on the UnPoller project.

Project Identity

Name: UnPoller (UniFi Poller)
Language: Go 1.25.5+
Purpose: Collect metrics and events from UniFi network controllers and export to monitoring backends
Repository: https://github.com/unpoller/unpoller
Documentation: https://unpoller.com

Architecture Overview

UnPoller uses a plugin-based architecture with a generic core that provides input/output interfaces. The core library (pkg/poller) has no knowledge of UniFi or specific backends - it's a generic plugin system.

Core Components

  1. Plugin System (pkg/poller/):

    • Generic input/output interfaces
    • Automatic plugin discovery via blank imports
    • Configuration management (TOML/JSON/YAML + env vars)
    • Metrics and events aggregation
  2. Input Plugins:

    • pkg/inputunifi/ - Collects data from UniFi controllers
  3. Output Plugins:

    • pkg/influxunifi/ - InfluxDB (v1 and v2)
    • pkg/promunifi/ - Prometheus
    • pkg/lokiunifi/ - Loki
    • pkg/datadogunifi/ - DataDog
    • pkg/mysqlunifi/ - MySQL
  4. Web Server (pkg/webserver/):

    • Health checks
    • Metrics endpoint
    • Plugin information

Code Organization

Directory Structure

unpoller/
├── main.go                    # Entry point, loads plugins
├── pkg/
│   ├── poller/               # Core plugin system (generic)
│   │   ├── config.go         # Configuration structures
│   │   ├── inputs.go         # Input plugin interface
│   │   ├── outputs.go        # Output plugin interface
│   │   ├── start.go          # Application startup
│   │   └── commands.go       # CLI commands
│   ├── inputunifi/           # UniFi input plugin
│   ├── influxunifi/          # InfluxDB output
│   ├── promunifi/            # Prometheus output
│   ├── lokiunifi/            # Loki output
│   ├── datadogunifi/         # DataDog output
│   ├── mysqlunifi/           # MySQL output
│   └── webserver/            # Web server
├── examples/                 # Configuration examples
├── init/                     # Init scripts (systemd, docker, etc.)
└── scripts/                  # Build scripts

Plugin Interface Pattern

Input Plugin:

type Input interface {
    GetMetrics() (*Metrics, error)
    GetEvents() (*Events, error)
}

Output Plugin:

type Output interface {
    WriteMetrics(*Metrics) error
    WriteEvents(*Events) error
}

Registration:

func init() {
    poller.RegisterInput(&MyInput{})
    // or
    poller.RegisterOutput(&MyOutput{})
}

Coding Standards

Go Style

  • Formatting: Standard gofmt
  • Linting: .golangci.yaml configuration
    • Enabled: nlreturn, revive, tagalign, testpackage, wsl_v5
  • Imports: Use //nolint:gci when import ordering needs exception

Naming Conventions

  • Packages: lowercase, single word
  • Exported: PascalCase
  • Unexported: camelCase
  • Constants: PascalCase with descriptive names
  • Errors: Always err, checked immediately

Error Handling

// ✅ Good
if err != nil {
    return fmt.Errorf("context: %w", err)
}

// ❌ Bad
_ = functionThatReturnsError()

Configuration Pattern

All configuration structs must include:

type Config struct {
    Field string `json:"field" toml:"field" xml:"field" yaml:"field"`
}
  • Environment variables use UP_ prefix (defined in ENVConfigPrefix)
  • Automatic unmarshaling via golift.io/cnfg and golift.io/cnfgfile

Testing

  • Tests in _test packages (enforced by testpackage linter)
  • Use github.com/stretchr/testify for assertions
  • Integration tests: integration_test.go with integration_test_expectations.yaml

Key Dependencies

Core Libraries

  • github.com/unpoller/unifi/v5 - UniFi API client (local: /Users/briangates/unifi)
  • golift.io/cnfg - Configuration management
  • golift.io/cnfgfile - Config file parsing
  • github.com/spf13/pflag - CLI flags
  • github.com/gorilla/mux - HTTP router

Output Backends

  • InfluxDB: github.com/influxdata/influxdb1-client (v1), github.com/influxdata/influxdb-client-go/v2 (v2)
  • Prometheus: github.com/prometheus/client_golang
  • DataDog: github.com/DataDog/datadog-go/v5
  • Loki: Custom HTTP implementation

Data Structures

Metrics

type Metrics struct {
    TS             time.Time
    Sites          []any
    Clients        []any
    SitesDPI       []any
    ClientsDPI     []any
    Devices        []any
    RogueAPs       []any
    SpeedTests     []any
    CountryTraffic []any
}

Events

type Events struct {
    Logs []any
}

Device Types

UniFi devices supported:

  • UAP - Access Points (uap.go)
  • USG - Security Gateways (usg.go)
  • USW - Switches (usw.go)
  • UDM - Dream Machines (udm.go)
  • UXG - Next-Gen Gateways (uxg.go)
  • UBB - Building Bridges (ubb.go)
  • UCI - Industrial devices (uci.go)
  • PDU - Power Distribution Units (pdu.go)

Each output plugin has device-specific reporting functions following the pattern:

func (r *Report) UAP(uaps []*unifi.UAP) {
    // Convert and export UAP data
}

Common Development Tasks

Adding a New Output Plugin

  1. Create package in pkg/myoutput/
  2. Implement Output interface
  3. Register in init() function
  4. Add blank import to main.go: _ "github.com/unpoller/unpoller/pkg/myoutput"
  5. Add configuration struct with tags
  6. Create README.md with usage examples

Adding Device Type Support

  1. Add device-specific file (e.g., mydevice.go)
  2. Follow pattern from existing device files
  3. Convert UniFi device struct to output format
  4. Handle errors appropriately

Modifying Configuration

  1. Add fields to appropriate config struct
  2. Include all format tags: json, toml, xml, yaml
  3. Update example configs in examples/
  4. Document in package README.md

Build & Deployment

  • CI/CD: GitHub Actions (.github/workflows/)
  • Build: goreleaser (.goreleaser.yaml)
  • Platforms: Linux, macOS, Windows, FreeBSD
  • Docker: Auto-built to ghcr.io
  • Packages: Debian, RedHat via goreleaser
  • Homebrew: Formula for macOS

Important Constraints

  1. Generic Core: pkg/poller must remain generic - no UniFi/backend knowledge
  2. Cross-Platform: Support Windows, macOS, Linux, BSD
  3. Configuration: Support TOML (default), JSON, YAML, and environment variables
  4. Error Handling: Always check and return errors
  5. Context: Use context.Context for cancellable operations
  6. Timeouts: Respect timeouts and deadlines
  7. Logging: Use structured logging via logger interfaces

Configuration Examples

File Formats: See examples/up.conf.example, examples/up.json.example, examples/up.yaml.example

Environment Variables:

UP_INFLUX_URL=http://localhost:8086
UP_UNIFI_DEFAULT_USER=admin
UP_UNIFI_DEFAULT_PASS=password
UP_POLLER_DEBUG=true
UP_POLLER_INTERVAL=30s

When Writing Code

  1. Follow Existing Patterns: Look at similar plugins for examples
  2. Keep Core Generic: Don't add UniFi/backend-specific code to pkg/poller
  3. Error Handling: Check all errors, return descriptive messages
  4. Documentation: Document exported functions and types
  5. Testing: Write tests in _test packages
  6. Cross-Platform: Test on multiple platforms when possible
  7. Performance: Consider polling intervals and data volume
  8. Security: Don't log passwords or sensitive data

Resources