# AGENTS.md This file provides guidelines for agentic coding agents working on the agentmon repository. ## Build/Lint/Test Commands ```bash # Run all tests go test ./... # Run tests for a specific package go test ./internal/event # Run a single test go test ./internal/event -run TestValidate_ValidEvent # Run tests with verbose output go test -v ./... # Tidy dependencies go mod tidy # Run services via Makefile make tidy make test make run-ingest # Ingest gateway (requires NATS_URL, NATS_TOPIC) make run-query # Query API (requires DATABASE_URL) make run-ui # Web UI make run-processor # Event processor (requires DATABASE_URL, NATS_URL, NATS_TOPIC) # Build executables go build -o ingest-gateway ./cmd/ingest-gateway go build -o query-api ./cmd/query-api go build -o web-ui ./cmd/web-ui ``` ## Code Style Guidelines ### Imports - Order: stdlib, internal packages, external packages - Group by blank line between each section - No unused imports Example: ```go import ( "context" "database/sql" "agentmon/internal/event" "agentmon/internal/httpx" "github.com/go-chi/chi/v5" "github.com/jackc/pgx/v5" ) ``` ### Formatting - Use `go fmt` or enable auto-formatting - Standard Go formatting rules apply - No inline comments unless necessary ### Types - Use `any` for generic types (not `interface{}`) - Use pointer types (`*int64`) for optional JSON fields - Struct tags for JSON serialization: `json:"field_name,omitempty"` - Use `sql.ErrNoRows` for "not found" database errors ### Naming Conventions - Exported: CamelCase (e.g., `ValidationError`, `Publish`) - Unexported: camelCase (e.g., `db`, `validate`) - Acronyms: keep uppercase (e.g., `DB`, `NATS`, `URL`) - Constants: CamelCase (e.g., `validTypes`) - Test functions: `Test_` ### Error Handling - Always check errors, don't ignore - Use `log.Fatalf` for startup errors (main package only) - Use `errors.As()` for type assertions: `errors.As(err, &ve)` - Custom error types must implement `Error() string` method - Return errors from functions, handle at call site - HTTP errors: return JSON with error field, appropriate status code Example: ```go if err != nil { return nil, fmt.Errorf("operation failed: %w", err) } if ve, ok := err.(ValidationError); ok { return ValidationError{Field: "field", Message: "message"} } ``` ### Database - Use `context.Context` for all DB operations - Use pgx/v5 via stdlib interface: `sql.Open("pgx", url)` - Check `sql.ErrNoRows` explicitly for not-found cases - Always defer `db.Close()` in main functions ### HTTP - Use chi router with middleware - Standard middleware chain: `RequestID`, `RealIP`, `Logger`, `Recoverer` - Health check endpoint: `GET /healthz` returns 200 with "ok" - JSON responses: use `httpx.WriteJSON(w, status, data)` - Get path params: `chi.URLParam(r, "paramName")` - Get query params: `r.URL.Query().Get("key")` ### Configuration - Use environment variables for configuration - Helper pattern: `envDefault(key, defaultValue)` function - Required env vars: log.Fatal if missing - Optional env vars: provide sensible defaults ### Validation - Validate all input (HTTP, events) - Return structured errors with field path and message - Type assertion with comma-ok for error type checking - Valid event types: `session.start`, `session.end`, `run.start`, `run.end`, `span.start`, `span.end`, `error`, `metric.snapshot` ### Testing - Use standard `testing` package - Test file naming: `*_test.go` - Test function naming: `Test_` - Use `t.Fatalf` for setup failures - Use `t.Fatal` for assertion failures (not `t.Error`) - Minimal test structure: setup, act, assert Example: ```go func TestValidate_ValidEvent(t *testing.T) { raw := `{"schema": {"name": "agentmon.event", "version": 1}}` var m map[string]any _ = json.Unmarshal([]byte(raw), &m) err := Validate(m) if err != nil { t.Fatalf("expected no error, got %v", err) } } ``` ### Context Usage - Pass `context.Context` to functions that do I/O or external calls - Use `context.WithTimeout` for operations with deadlines - Defer cancel functions - Example: `ctx, cancel := context.WithTimeout(ctx, 5*time.Second)` ### Package Structure - `cmd/`: Executable entry points (main packages) - `internal/`: Internal packages not imported by external code - `internal/event/`: Event schema and validation - `internal/httpx/`: HTTP utilities - `internal/store/postgres/`: Database operations - `internal/queue/nats/`: NATS publishing ### JSON Handling - Decode to `map[string]any` for flexible event processing - Type assertions: `if v, ok := m["key"].(string); ok {}` - Use `json.RawMessage` for buffering JSON data - JSON encoder/decoder for I/O ### Logging - Use `log.Printf` for general logging - Use `log.Fatalf` for unrecoverable errors in main - Minimal logging in packages (prefer returning errors)