Imported from C2FO/vfs (
AGENTS.md). Install upstream withnpx skills add C2FO/vfs. Copyright stays with the author.
Agent Guidelines for VFS Repository
This document provides guidelines for AI agents working on the VFS repository, including upgrade policies, dependency management, and maintenance procedures.
Table of Contents
- Development Guidelines
- CHANGELOG and PR Process
- Go Version Policy
- Dependency Upgrades
- GitHub Actions Maintenance
- Module Management
Development Guidelines
Testing Requirements
Mandatory Test Coverage
- All new code MUST have tests
- Aim for coverage as close to 100% as is practicable
- Minimum thresholds (enforced by CI):
- Total project coverage: 80%
- Package coverage: 63%
- File coverage: 52%
Test Organization
- Use
testify/suitefor organizing related tests- One test suite per major component/struct being tested
- Naming:
[ComponentName]TestSuite(e.g.,S3BackendTestSuite) - Use
SetupTest()andTearDownTest()for test isolation - Exception: testify/suite may not be suitable for benchmarks or simple unit tests
Test Style
-
Prefer suite functions and facilities over external libraries
- Use suite's built-in methods for temp files, fixtures, etc.
- Use
s.Assert()ands.Require()from suite rather than standalone packages - Keep test dependencies minimal
-
Use table-driven tests where possible
- Slice of anonymous structs with
name, inputs, and expected outputs - Use descriptive test case names that explain the scenario
- Example:
tests := []struct { name string input string expectedOutput string expectedError string }{ { name: "Success case - normal operation", input: "valid", expectedOutput: "result", }, { name: "Error case - invalid input", input: "invalid", expectedError: "expected error message", }, } for _, tt := range tests { s.Run(tt.name, func() { result, err := functionUnderTest(tt.input) if tt.expectedError != "" { s.Require().Error(err) s.Assert().Contains(err.Error(), tt.expectedError) } else { s.Require().NoError(err) s.Assert().Equal(tt.expectedOutput, result) } }) }
- Slice of anonymous structs with
Integration Tests
- Use build tag
vfsintegrationfor integration tests - Run with:
go test -tags=vfsintegration ./... - Integration tests may require external services or credentials
Code Quality
Linting
- All code MUST pass
golangci-lint - Run before committing:
make lint - Configuration:
.golangci.yml - Linter runs on all modules independently in CI
Code Style
- Follow standard Go idioms and conventions
- Use
gofmtandgoimportsfor formatting - Exported functions and types must have documentation comments
- Keep functions focused and small
- Use early returns to reduce nesting
Error Handling
- Handle all errors explicitly - no silent failures
- Use wrapped errors with context:
fmt.Errorf("operation failed: %w", err) - Provide meaningful error messages with context
- Never ignore error return values
Interface Design
- Prefer small, focused interfaces over large ones
- Define interfaces in consuming packages, not implementing packages
- Use dependency injection for testability
File Organization
- Group related functionality in packages
- Use subdirectories for different implementations
- Place mocks in
mocks/subdirectories - One package per major feature
Mocking
- Use
mockeryv3 for generating mocks with EXPECT() pattern - No manual mocks or fakes (unless absolutely necessary)
- Prefer EXPECT() pattern for mock setup for better readability and type safety
- Place mocks in dedicated
mocks/subdirectories - Generate mocks with:
//go:generate mockery --name=InterfaceName --output=./mocks - Example EXPECT() usage:
mockClient := mocks.NewMockSQSClient(t) mockClient.EXPECT().ReceiveMessage(mock.Anything, mock.MatchedBy(func(input *sqs.ReceiveMessageInput) bool { return *input.QueueUrl == queueURL })).Return(&sqs.ReceiveMessageOutput{Messages: messages}, nil)
Documentation
- All exported types, functions, and methods must have godoc comments
- Include usage examples for complex functionality
- Update README.md when adding new features
- Document breaking changes in CHANGELOG.md
Performance
- Implement graceful shutdown with timeouts
- Use context for cancellation throughout
- Prevent resource leaks with proper cleanup (use
defer) - Be mindful of goroutine lifecycle and synchronization
CHANGELOG and PR Process
CHANGELOG Requirements
All PRs MUST Update CHANGELOG.md
- Every PR requires an update to the
## [Unreleased]section of CHANGELOG.md - PRs are always submitted without a new version number
- Version numbers are added automatically when the PR is merged to main
CHANGELOG Format
The CHANGELOG follows Keep a Changelog format.
Standard Section Headings (case-insensitive):
### Added- New features or functionality### Changed- Changes to existing functionality (breaking changes only)### Removed- Removed features or functionality (breaking changes only)### Deprecated- Features marked for future removal### Security- Security-related updates or fixes### Fixed- Bug fixes
Breaking Changes
### Changedand### Removedsections are ONLY for breaking changes- MUST include the exact phrase "BREAKING CHANGE" in the description
- If a change is not breaking, use
### Added(for new features) or### Fixed(for bug fixes) - Example:
### Changed - **BREAKING CHANGE**: Modified API behavior to return errors instead of panicking
Version Bump Rules
Changes determine the next semantic version:
- Major bump:
### Changedor### Removedsections with "BREAKING CHANGE" - Minor bump:
### Added,### Deprecated, or### Securitysections - Patch bump: Only
### Fixedsections
Example CHANGELOG Entry
## [Unreleased]
### Added
- New S3 backend option for custom endpoint configuration
### Fixed
- Fixed file handle leak in os backend when operations fail
- Corrected path separator handling on Windows
PR Submission Guidelines
- Add changes under
## [Unreleased]section in CHANGELOG.md - Use appropriate section headings based on change type
- Do NOT add version numbers - these are added during the merge/release process
- Be clear and specific in change descriptions
- Mark breaking changes with "BREAKING CHANGE" text
Go Version Policy
Compatibility Requirements
VFS guarantees compatibility with the latest Go version minus 1 minor version.
Example: If Go 1.26.1 is the latest release, VFS supports:
- Go 1.26.x (latest minor version)
- Go 1.25.x (latest - 1 minor version)
The go.mod file specifies the older of the two supported versions (e.g., go 1.25.8), ensuring compatibility with both.
Upgrade Process
Core Module First
- Update
go.modin the root module to the latest Go version (e.g.,go 1.25.8) - Update all configuration files that reference Go versions
- Release the core VFS version
- Then update contrib modules (they import core, so core must be released first)
Configuration Files to Update
When updating Go versions, update these files:
go.mod- Main module Go version.golangci.yml-run.gofield.github/workflows/go.yml-matrix.go-versionarray.github/workflows/golangci-lint.yml-go-versionfield.github/workflows/codeql.yml-go-versionfield
Contrib Modules (Update After Core Release)
contrib/lockfile/go.modcontrib/vfsevents/go.modcontrib/backend/dropbox/go.mod- Any other contrib modules
Dependency Upgrades
General Policy
- Update dependencies regularly for security and bug fixes
- Test thoroughly after dependency updates
- Document breaking changes in CHANGELOG.md
Go Dependencies
# Update all dependencies
go get -u -t ./...
go mod tidy
# Update specific dependency
go get -u github.com/example/package@latest
GitHub Actions Maintenance
SHA Pinning Policy
All GitHub Actions must be pinned to specific commit SHAs for security and reproducibility.
Format: uses: owner/action@<sha> # <version-tag>
Example: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Update Policy
- Select the newest version that is at least 10 days old
- If the latest version is too recent (< 10 days), check for intermediate versions
- Allow time for community vetting of new releases
- Check for security advisories before updating
- Always verify release dates before updating
How to Update Actions
-
Find Available Versions
- Visit the action's repository releases page
- Example:
https://github.com/actions/checkout/releases - Check the CHANGELOG if available for release dates
-
Select Newest Eligible Version
- Identify all versions newer than current
- Find the newest version that is at least 10 days old
- If the latest is too recent, look for intermediate versions
- This allows time for community feedback and security review
-
Get the Commit SHA
- Navigate to the selected tag/release on GitHub
- Click on the commit hash to get the full 40-character SHA
- Copy the full SHA (not the abbreviated version)
-
Update the Workflow File
# Before uses: actions/checkout@old-sha # v6.0.1 # After uses: actions/checkout@new-sha # v6.0.2 -
Test the Workflow
- Create a PR to test the updated action
- Verify all workflows pass successfully
Workflow Files
.github/workflows/go.yml- Main test workflow (multi-module, multi-OS, multi-Go-version).github/workflows/golangci-lint.yml- Linting workflow.github/workflows/codeql.yml- Security scanning.github/workflows/go-test-coverage.yml- Test coverage enforcement.github/workflows/ensure_changelog.yml- CHANGELOG validation
Module Management
Repository Structure
VFS uses a multi-module repository structure:
vfs/
├── go.mod # Core VFS module
├── contrib/
│ ├── lockfile/go.mod # Lockfile contrib module
│ ├── vfsevents/go.mod # Events contrib module
│ └── backend/
│ └── dropbox/go.mod # Dropbox backend contrib module
Module Dependencies
- Contrib modules depend on core VFS
- Core must be released before updating contrib module imports
- Each module has independent versioning
Release Process
- Update and test core VFS module
- Create release tag for core (e.g.,
v7.14.0) - Update contrib modules to reference new core version
- Test contrib modules
- Create release tags for contrib modules (e.g.,
contrib/lockfile/v1.2.0)
Testing All Modules
# Run tests for all modules
make test
# Run linter for all modules
make lint
# Manual testing
for dir in $(find . -name go.mod -exec dirname {} \;); do
echo "Testing $dir"
(cd "$dir" && go test ./...)
done
CI/CD Configuration
Dynamic Module Detection
The CI workflows automatically detect all modules using:
- name: Find all modules
run: |
modules=$(find . -name go.mod -exec dirname {} \; | jq --raw-input --slurp --compact-output 'split("\n")[:-1]')
echo "modules=$modules" >> $GITHUB_OUTPUT
This ensures new modules are automatically tested without workflow updates.
Test Matrix
- Go Versions: 1.25, 1.26 (latest-1 and latest)
- Operating Systems: ubuntu-latest, macos-latest, windows-latest
- Modules: All modules with
go.modfiles
Concurrency Control
Workflows use concurrency groups to prevent resource waste:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
Code Quality
golangci-lint Configuration
- Configuration:
.golangci.yml - Go version must match latest supported version
- Runs on all modules independently
- Build tags:
vfsintegrationfor integration tests
Run the linter:
golangci-lint run --verbose --max-same-issues 0 ./...
Test Coverage
- Minimum coverage requirements defined in
.testcoverage.yml - Enforced via
go-test-coverageaction - Coverage reports generated for all modules
Security
Dependency Scanning
- CodeQL runs on all PRs and weekly schedule
- Scans for security vulnerabilities in Go code
- Requires
GH_CI_READsecret for private dependencies
Action Security
- All actions pinned to commit SHAs (not tags)
- Regular review of action updates
- 10-day waiting period for new releases
Maintenance Checklist
Monthly
- Check for Go version updates
- Review dependency updates (
go list -u -m all) - Check GitHub Actions for updates (>10 days old)
- Review security advisories
Quarterly
- Update Go to latest stable version
- Update all dependencies
- Review and update CI/CD workflows
- Update this AGENTS.md document
Before Major Release
- Update CHANGELOG.md
- Run full test suite on all platforms
- Verify all modules build successfully
- Update version tags
- Create GitHub release with notes
Common Tasks
Adding a New Contrib Module
- Create directory under
contrib/ - Initialize
go.modwith dependency on core VFS - Add README.md with usage documentation
- Implement required interfaces
- Add comprehensive tests
- CI will automatically detect and test the new module
Updating Core VFS Version in Contrib
cd contrib/yourmodule
go get github.com/c2fo/vfs/v7@v7.14.0
go mod tidy
Running Integration Tests
# With build tags
go test -tags=vfsintegration ./...
# Specific backend
cd backend/s3
go test -tags=vfsintegration ./...