Skip to content

Latest commit

 

History

History
179 lines (139 loc) · 4.15 KB

File metadata and controls

179 lines (139 loc) · 4.15 KB

AGENTS.md – Alpf Project Standards

Go Code Style & Conventions

Type Assertions

  • Use any instead of interface{} (Go 1.18+)
  • Correct: map[string]any
  • Avoid: map[string]interface{}

Function Comments

  • Place a summary comment above the function declaration
  • Do not use sequential step comments (// step 1, // step 2, etc)
  • The function comment should concisely explain what the function does, not how
  • Include inputs, outputs, and notable behavior (e.g., side effects, locking)

Example:

// LoadState reads .alpf/state.json with a shared lock to prevent concurrent writes.
// Returns an error if the file cannot be read or parsed.
func LoadState(projectPath string) (*pkg.ExecutionState, error) {
	statePath := filepath.Join(projectPath, ".alpf", "state.json")
	
	f, err := os.Open(statePath)
	if err != nil {
		return nil, fmt.Errorf("failed to open state file: %w", err)
	}
	defer f.Close()
	
	// Implementation details...
}

Control Flow Simplification

  • Use min() and max() builtins (Go 1.21+) instead of if/else for simple comparisons
  • Correct: delay = min(calculated, maxDelay)
  • Avoid:
    if calculated > maxDelay {
        delay = maxDelay
    } else {
        delay = calculated
    }

Error Handling

  • Always wrap errors with context using fmt.Errorf("context: %w", err)
  • Return errors early, don't nest deeply
  • Use meaningful error messages that indicate which operation failed

Imports

  • Group imports: stdlib, then external packages, separated by blank lines
  • Use goimports or manually organize if needed

Variable Naming

  • Use descriptive names; avoid single-letter vars except in loops (i, j, k)
  • Acronyms: ID not Id, JSON not Json, HTTP not Http
  • Prefer projectPath over p or path

Running the Project

Prerequisites

  • Go 1.25.4 or later
  • Cobra CLI framework (included via go.mod)

Build

go build -o alpf ./cmd/alpf

Run

./alpf [flags] [args]

Install

go install ./cmd/alpf

Running Tests

All Tests

go test ./...

Specific Package

go test ./internal/store
go test ./internal/executor

With Verbose Output

go test -v ./...

With Coverage

go test -cover ./...
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

Run Specific Test

go test -run TestFunctionName ./internal/store

Watch Mode (with entr or similar)

find . -name "*.go" | entr go test ./...

Key Design Patterns

Configuration & State

  • Config: Static configuration (loaded once at startup)
  • ExecutionState: Dynamic runtime state (persisted to .alpf/state.json)
  • AttemptRecord: Individual attempt history (appended to .alpf/history.jsonl)

Locking Strategy

  • Shared lock: When reading state (multiple readers allowed)
  • Exclusive lock: When writing state (single writer)
  • Always defer unlock immediately after acquiring lock

Error Propagation

  • Return errors from functions
  • Wrap with context using %w format
  • Only log/handle errors at the boundary (CLI level)

Maps with Dynamic Configs

  • Use map[string]any for flexible validator/executor configs
  • Type assert values when accessing: config["key"].(string)

Common Tasks

Adding a New Function

  1. Write concise doc comment above function
  2. Use consistent parameter order: context-like params first, then data params
  3. Return values last, error last
  4. Simplify control flow (use min/max, avoid unnecessary nesting)

Adding a New Test

  1. Place in same package as code being tested
  2. Name file *_test.go
  3. Use TestFunctionName convention
  4. Test both happy path and error cases

Modifying Error Messages

  • Include the operation that failed: "failed to open config file: %w"
  • Use lowercase unless it's a proper noun

Linting & Formatting

Format Code

go fmt ./...

Lint with golangci-lint (if installed)

golangci-lint run ./...

Common Warnings to Fix

  • interface{} → use any
  • If/else for min/max → use builtin min() / max()
  • Unused variables → remove or use _