This file provides guidance to AI Agents when working with code in this repository.
All of our documentation is at https://docs.flipt.io. Weigh the v2 docs heavily when answering questions over the v1 docs.
Flipt v2 is a Git-native feature management platform with a monorepo structure. This is the v2 version with a Git-native architecture.
- v1 code: Located on
mainbranch - v2 code: Located on current (
v2) branch. This is the default branch in the repository. - License: Fair Core License for server, MIT for client code
- Requirements: Go 1.25+ and Node.js 18+
cmd/flipt/- Main application entry pointcore/- Core validation and business logicerrors/- Shared error definitionsinternal/- Core application logic (not importable)cmd/- Internal command utilities and code generation toolscommon/- Shared types and utilities across internal packagesconfig/- Configuration managementcontainers/- Container test utilitiescoss/- Commercial open source features (license management, enterprise storage, secrets)secrets/- Secret management system with provider interface (OSS file provider, Pro Vault provider)credentials/- Credential management for cloud storage and Git authenticationext/- Import/export functionality for flags and segmentsgateway/- HTTP gateway implementationinfo/- Version and build informationmigrations/- Database migration files (ClickHouse for analytics)otel/- OpenTelemetry integration (logs, metrics, traces)product/- Product metadata and feature flagsrelease/- Release version checkingserver/- gRPC and HTTP server implementationsanalytics/- Analytics collection server (Prometheus, ClickHouse)authn/- Authentication server and middlewareauthz/- Authorization server with Rego engineenvironments/- Environment management serverevaluation/- Flag evaluation server with OFREP supportmetadata/- Metadata API server
storage/- Storage abstractions and implementationsanalytics/- Analytics data storageauthn/- Authentication storage (Redis, memory, static)environments/- Environment-aware storage with Git supportfs/- File system abstraction layergit/- Git repository management
telemetry/- Usage telemetry collection
rpc/- Protocol buffer definitions and generated codeflipt/- Main Flipt API (v1)v2/- V2 APIs (environments, analytics, evaluation)
sdk/- Client SDKs (Go SDK included)ui/- React/TypeScript frontend
Multi-backend storage supporting:
- Git repositories (primary for v2)
- File system (local development)
- Cloud storage (S3, GCS, Azure Blob) - Flipt config only
- Environment-per-branch: Map Git branches to environments
- Environment-per-directory: Organize by microservice/team
- Environment-per-repository: Separate repos for products
- gRPC API (port 9000) - Primary interface
- REST API (port 8080) - HTTP gateway over gRPC
- OpenFeature compatible evaluation
- Evaluation API:
/api/v1/evaluate- Evaluate feature flags - Management API: Full CRUD operations on flags, segments, rules
- Analytics API:
/api/v2/analytics- Flag evaluation metrics - Environments API:
/api/v2/environments- Environment management - OFREP API:
/ofrep/v1- OpenFeature Remote Evaluation Protocol
- React 19 with TypeScript
- Redux Toolkit for state management
- Tailwind CSS for styling
- Vite for build tooling
- React Router for navigation
# Install required development tools
mage bootstrap- Setup: Run
mage bootstrapto install tools - Backend Development:
- Use
mage go:runfor server - Server runs on port 8080 (HTTP) and 9000 (gRPC)
- Use
- Frontend Development:
- Run
mage ui:runfor UI dev server on port 5173 - UI proxies API requests to backend on port 8080
- Run
- Full Development: Run both servers simultaneously
mage build- Builds the project similar to a release build (default target)mage go:build- Builds Go server for development without bundling assetsmage go:run- Runs Go server in development mode with local configmage dev- Alias for go:run./bin/flipt server --config config/local.yml- Run built binary with local config
mage ui:deps- Install UI dependenciesmage ui:run- Run UI in development mode (port 5173)mage ui:dev- Alias for ui:runmage ui:build- Build UI assets for releasecd ui && npm run dev- Alternative way to run UI dev server
mage go:test- Run all Go unit testsgo test -v {path} -run {test}- Run a specific Go testmage go:bench- Run Go benchmarking testsmage go:cover- Run tests and generate coverage reportcd ui && npm run test- Run UI unit tests (Jest)
mage go:lint- Run Go linters (golangci-lint and buf lint)mage go:fmt- Format Go code with goimportsmage ui:lint- Run UI linters (ESLint)mage ui:fmt- Format UI code (Prettier)
mage go:proto- Generate protobuf files and gRPC stubsmage go:mockery- Generate mocksmage go:generate- Generate both mocks and proto files
mage clean- Clean built files and tidy go.modmage prep- Prepare project for building (clean + ui:build)
- Protocol buffers generate Go and gateway code
- Mockery generates Go test mocks. See .mockery.yml
- UI has no code generation
All Go code should follow the Google Go Style Guide as the base style guide.
The guidelines below are Flipt-specific conventions that build upon the Google style guide. When in doubt, refer to the Google guide first, then apply these project-specific patterns.
Key areas from the Google guide to pay special attention to:
- Formatting: Use
gofmt(we usegoimportswhich includesgofmt) - Naming: Follow Go naming conventions for packages, types, functions, and variables
- Package organization: Keep packages focused and avoid circular dependencies
- Error handling: Return errors as the last return value, handle errors explicitly
- Documentation: Write clear godoc comments for exported types and functions
- Public functions: Use PascalCase (
NewServer,ListFlags,RegisterGRPC) - Private functions: Use camelCase (
getStore,buildConfig,handleError) - Factory functions: Use
Newprefix for constructors (NewRepository,NewEnvironmentFactory) - Variables: Use camelCase (
environmentKey,namespaceKey,startTime) - Constants: Use PascalCase for exported, camelCase for unexported
- Interfaces: Use descriptive names (
Store,EnvironmentStore,Validator)
// Prefer := for single variable declarations
result := SomeType{}
// Use var blocks for multiple related variables
var (
environmentKey = r.EnvironmentKey
namespaceKey = r.NamespaceKey
startTime = time.Now().UTC()
)Use constants when appropriate for values that are unlikely to change. Even in tests.
❌ Bad Examples
var (
maxRetries = 3
secretProvider = "vault"
) maxRetries := 3
secretProvider := "vault"✅ Good Example
const (
maxRetries = 3
secretProvider = "vault"
)Use the custom error types when possible:
// Preferred - use custom error types
return nil, errs.ErrNotFoundf("flag %q not found", key)
return nil, errs.ErrInvalidf("invalid configuration: %s", reason)
// Fallback - standard error handling
return nil, fmt.Errorf("failed to process: %w", err)Prefer inline error declarations and checking when it makes sense.
❌ Bad Example
err := doSomething()
if err != nil {
// ...
}✅ Good Example
if err := doSomething(); err != nil {
// ...
}Follow the three-group import pattern (extends Google guide):
import (
// Standard library
"context"
"fmt"
"time"
// Third-party packages
"github.com/go-git/go-git/v6"
"go.uber.org/zap"
// Local packages
"go.flipt.io/flipt/errors"
"go.flipt.io/flipt/internal/config"
)Use structured logging with zap:
// Preferred - structured logging with context
s.logger.Debug("processing request",
zap.String("environment", envKey),
zap.String("namespace", nsKey),
zap.Int("count", len(items)))
// Use appropriate log levels
s.logger.Debug("debug info for development") // Most common
s.logger.Info("important application events")
s.logger.Warn("recoverable error conditions")
s.logger.Error("error conditions that need attention")
// Avoid overusing log statements - be selective about what to log// Public functions need godoc comments starting with function name
// ListFlags lists all flags in the specified environment and namespace
func (s *Server) ListFlags(ctx context.Context, r *flipt.ListFlagRequest) (*flipt.FlagList, error) {
// Inline comments explain complex logic
// Check for X-Environment header for backward compatibility
environmentKey := r.EnvironmentKey
if headerEnv, ok := common.FliptEnvironmentFromContext(ctx); ok && headerEnv != "" {
environmentKey = headerEnv
}
}- Use
internal/for private packages that shouldn't be imported externally - Organize by domain (
server/,storage/,config/,analytics/) - Keep interfaces in domain root, implementations in subdirectories
- Co-locate tests with implementation (
*_test.go) - Use
testdata/directories for test fixtures
Always run these commands when adding or editing Go code:
# Format Go code
mage go:fmt
# Lint Go code
mage go:lint
# Run modernize to update code to 1.24+ style
mage go:modernize- Components: Use PascalCase for
.tsxfiles (FlagForm.tsx,FlagTable.tsx) - API files: Use camelCase with suffix (
flagsApi.ts,authApi.ts) - Types: Use PascalCase for
.tsfiles (Flag.ts,Analytics.ts) - Utilities: Use descriptive lowercase names (
helpers.ts)
- Use functional components with hooks
- Organize components by domain in directories
- Keep reusable UI components in
ui/directory - Co-locate component tests with implementation
- Use Redux Toolkit for application state
- Create API slices for domain-specific data (
flagsApi.ts) - Use TypeScript for type safety throughout
Always run these commands when adding or editing UI code:
# Format UI code (TypeScript/React)
mage ui:fmt
# Lint UI code (ESLint)
mage ui:lint# Format specific markdown files (replace with actual filename)
npx prettier -w README.mdconfig/local.yml- Local development configconfig/dev.yml- Alternative dev config- User config at
{{ USER_CONFIG_DIR }}/flipt/config.yml
- Use
FLIPT_LOG_LEVEL=debugfor verbose logging - Check
/metricsendpoint for Prometheus metrics - View OpenTelemetry traces for request flow
- Git sync issues: Check repository access and credentials
- Authentication issues: Verify redirect URLs and client configurations
- Go tests use testcontainers for unit tests that depend on external tools
- UI tests use Jest for unit tests and Playwright for E2E
When writing tests, ensure they actually verify the functionality being tested:
❌ Bad Example - Test doesn't verify actual behavior:
// This test only verifies the method runs without error, not that the logic works
func TestFeature(t *testing.T) {
result, err := service.DoSomething(input)
require.NoError(t, err)
assert.NotNil(t, result)
}✅ Good Example - Test verifies specific behavior:
// This test verifies the actual logic and behavior
func TestFeature(t *testing.T) {
// Use mock.MatchedBy to verify the correct data is passed through
store.On("Method", mock.MatchedBy(func(ctx context.Context) bool {
// Verify the context contains the expected values
value, ok := somePackage.ValueFromContext(ctx)
return ok && value == expectedValue
}), expectedArg).Return(expectedResult, nil)
result, err := service.DoSomething(input)
require.NoError(t, err)
// Verify the actual business logic worked correctly
assert.Equal(t, expectedOutput, result.ImportantField)
store.AssertExpectations(t) // Ensures mocks were called as expected
}Key Testing Principles:
- Verify behavior, not just success: Don't just check that methods return without error
- Test the logic: Use
mock.MatchedByto verify correct data flows through the system - Test edge cases: Include tests for when conditions are met vs. not met
- Use meaningful assertions: Assert on the specific values that matter to the business logic
- Mock verification: Use
mock.AssertExpectations(t)to ensure mocks were called with expected parameters
Follow conventional commit format:
type(scope): brief description
Longer description if needed explaining the why, not the what.
- List specific changes if helpful
- Include any breaking changes
- Reference issues (e.g., "Fixes #123")
feat:- New featuresfix:- Bug fixesdocs:- Documentation changesstyle:- Code style changes (formatting, etc.)refactor:- Code refactoring without functional changestest:- Adding or modifying testschore:- Build process or auxiliary tool changes
# Good commit messages
git commit -s -m "feat: add X-Environment header support to ListFlags endpoint
The v1 ListFlags endpoint now checks for X-Environment header
for backward compatibility. When present, the header value
takes precedence over the request environment parameter.
- Modified ListFlags method to check context for environment header
- Added ForwardFliptEnvironment middleware to v1 API gateway
- Added comprehensive test coverage
Fixes #4411"
git commit -s -m "fix: resolve race condition in flag evaluation cache"
git commit -s -m "test: improve X-Environment header test coverage
- Use mock.MatchedBy to verify context contains correct environment
- Add test for when header is not present
- Ensure tests actually validate the header precedence logic"Use the same conventional commit format for PR titles:
type(scope): brief description
## Summary
Brief description of what this PR does and why.
## Changes
- **Modified `file1.go`**: Specific change description
- **Added `file2_test.go`**: Test coverage description
- **Updated `config.yml`**: Configuration change description
## Backward Compatibility
Describe any backward compatibility or breaking change considerations.
## Additional Notes
Any other context, screenshots, or related issues.- Keep PRs focused: One logical change per PR
- Write descriptive titles: Use conventional commit format
- Provide context: Explain the "why" behind changes
- Include tests: Always add tests for new functionality
- Run quality checks: Format and lint before creating PR
- Reference issues: Use "Fixes #123" to auto-close issues
- Review your own PR: Look through the diff before requesting review
- Base PRs on the correct branch: Base PRs on the correct branch (e.g.
v2for v2 changes,mainfor v1 changes) - Label PRs correctly: When creating a feature based off of the v2 branch, label the PR with the
v2label. Similarly for a v1 (main) feature, use thev1label.
Before creating a PR, ensure:
- Code follows style guidelines
- Tests are added and passing
- Linting passes (
mage go:lint/mage ui:lint) - Code is formatted (
mage go:fmt/mage ui:fmt) - Commit messages are clear and descriptive
- PR description explains the change and its purpose