7.6 KiB
7.6 KiB
Contributing Guide
Development guidelines for the Agent Guardrails Template
Version: 2.6.0 Last Updated: 2026-02-15
Table of Contents
Getting Started
Important: All future development is in Go. Python implementation is deprecated as of v2.6.0.
Prerequisites
- Go 1.23+
- Docker or Podman
- PostgreSQL 16 (for local development)
- Redis 7 (for local development)
- Make
Repository Structure
mcp-server/
├── cmd/
│ └── server/ # Main application entry point
├── internal/
│ ├── team/ # Team management logic (Go)
│ ├── rules/ # Rule engine
│ ├── audit/ # Audit logging
│ ├── database/ # Database operations
│ ├── cache/ # Redis caching
│ ├── mcp/ # MCP protocol implementation
│ ├── web/ # HTTP handlers
│ ├── security/ # Secrets scanning
│ └── validation/ # Input validation
├── deploy/ # Deployment files
└── Makefile # Build automation
Go Development Workflow
Building
cd mcp-server
# Build the server binary
make build
# Build for production
make build-prod
# Clean build artifacts
make clean
Running Locally
# Install dependencies
make deps
# Run database migrations
export DATABASE_URL="postgresql://guardrails:password@localhost:5432/guardrails?sslmode=disable"
make migrate-up
# Run the server (requires PostgreSQL and Redis)
make dev
# Or run directly
go run ./cmd/server
Code Quality
# Format all Go code
make fmt
# Run linter (golangci-lint)
make lint
# Run tests
make test
# Run tests with coverage
make test-cover
# Check for vulnerabilities
make vuln
# Full check (fmt + lint + test)
make check
Code Standards
Go Code Style
All code must pass the following checks:
-
gofmt - Standard Go formatting
gofmt -w . -
go vet - Static analysis
go vet ./... -
golangci-lint - Comprehensive linting
golangci-lint run
Coding Conventions
- Package names: Short, lowercase, no underscores
- File names: lowercase_with_underscores.go
- Interface names: Where possible, end with
-er(e.g.,Reader,Writer) - Exported names: PascalCase
- Unexported names: camelCase
- Constants: PascalCase or ALL_CAPS for exported
Example
// Good package name
package team
// Good interface name
type Manager interface {
AssignRole(project, team, role, person string) error
GetStatus(project string) (Status, error)
}
// Good struct and method names
type teamManager struct {
db database.Store
cache cache.Cache
}
func (tm *teamManager) AssignRole(project, team, role, person string) error {
// implementation
}
Error Handling
- Always check errors
- Wrap errors with context using
fmt.Errorfwith%w - Use custom error types for business logic errors
// Good
if err := tm.db.AssignRole(ctx, project, team, role, person); err != nil {
return fmt.Errorf("failed to assign role: %w", err)
}
// Custom error type
var ErrTeamFull = errors.New("team is at maximum capacity")
if len(members) >= maxTeamSize {
return ErrTeamFull
}
Testing
Test Structure
mcp-server/internal/team/
├── team.go # Implementation
└── team_test.go # Tests
Running Tests
# All tests
make test
# Specific package
go test ./internal/team/...
# With verbose output
go test -v ./internal/team/...
# Race detection
go test -race ./...
# Benchmarks
go test -bench=. ./...
Test Coverage
Minimum coverage requirements:
- Core packages (
internal/team,internal/rules): 80%+ - Handlers (
internal/web): 70%+ - Utilities: 60%+
# Generate coverage report
make test-cover
# View in browser
go tool cover -html=coverage.out
Test Guidelines
- Use table-driven tests where possible
- Mock external dependencies (database, cache)
- Test both success and error paths
- Use meaningful test names
func TestAssignRole(t *testing.T) {
tests := []struct {
name string
project string
team string
role string
person string
wantErr error
}{
{
name: "valid assignment",
project: "test-project",
team: "team-1",
role: "lead",
person: "alice",
wantErr: nil,
},
{
name: "team full",
project: "test-project",
team: "team-1",
role: "developer",
person: "bob",
wantErr: ErrTeamFull,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tm := NewManager(mockDB, mockCache)
err := tm.AssignRole(tt.project, tt.team, tt.role, tt.person)
if !errors.Is(err, tt.wantErr) {
t.Errorf("AssignRole() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
Commit Guidelines
Conventional Commits
Follow the Conventional Commits specification:
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
Types
feat: New featurefix: Bug fixdocs: Documentation changesstyle: Code style changes (formatting, no logic change)refactor: Code refactoringtest: Test additions or updateschore: Build process or auxiliary tool changesperf: Performance improvementssecurity: Security fixes
Examples
feat(team): add team size validation
Implements TEAM-007 compliance check for maximum team size.
Adds validation to prevent over-allocation.
fix(mcp): resolve session timeout handling
docs(api): update endpoint documentation
refactor(database): simplify transaction handling
test(audit): add coverage for audit logging
Scope Values
Common scopes for this project:
team: Team managementmcp: MCP protocolweb: Web handlersdatabase: Database operationscache: Redis/cachesecurity: Security featuresconfig: Configurationdeploy: Deployment
Migration Notice
Python to Go Migration (v2.6.0)
Status: Complete
What Changed:
scripts/team_manager.py->mcp-server/internal/team/(Go package)- All team management logic now in Go
- Database migrations via golang-migrate
- No Python runtime required
How to Contribute:
- Write Go code in
mcp-server/internal/ - Follow Go conventions and this guide
- Run
make checkbefore committing - Ensure tests pass with
make test
Benefits:
- Smaller container size (~50MB vs ~500MB)
- Faster startup (~100ms vs ~3s)
- Distroless security hardening
- Single static binary
See Also:
- PYTHON_MIGRATION.md - Detailed migration guide
- ARCHITECTURE.md - System architecture
- MIGRATION.md - Version migration procedures
Getting Help
- Documentation: Start with INDEX_MAP.md
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Last Updated: 2026-02-15 Version: 2.6.0 Implementation: Go (mcp-server/internal/)