Skip to content

Contributing

Thank you for your interest in contributing to FinFocus Core! This document provides guidelines and instructions for contributing code, documentation, and feedback.

This project is licensed under the Apache License 2.0.

By contributing to FinFocus Core, you agree that your contributions will be licensed under the same terms. See the LICENSE file for the full license text.

New features, capabilities, and architectural changes must use SpecKit for specification-driven development. This ensures features are well-planned, documented, and testable.

Minor bug fixes and small improvements do not require SpecKit. You may submit a pull request directly.

What qualifies as a minor bug fix:

  • Typo corrections in code or documentation
  • Small logic fixes that don’t change APIs
  • Documentation corrections or clarifications
  • Dependency updates for security patches
  • Test improvements and additional test coverage
  • Performance optimizations without API changes

What requires SpecKit:

  • New CLI commands or flags
  • New features or capabilities
  • API changes or new endpoints
  • Architectural modifications
  • Changes affecting the plugin protocol
  • New integrations or data sources
ToolVersionPurpose
Go1.25.8+Core development
golangci-lintv2.11.4Go linting
markdownlint-cliv0.45.0Markdown linting
GitLatestVersion control
MakeLatestBuild automation
Node.jsLatest LTSDocumentation tools

Install Go (if not already installed):

Download from go.dev/dl

Install golangci-lint:

Terminal window
LINT_URL="https://raw.githubusercontent.com/golangci/golangci-lint"
curl -sSfL "${LINT_URL}/HEAD/install.sh" | sh -s -- -b "$HOME/go/bin" v2.11.4

Install markdownlint-cli:

Terminal window
npm install -g markdownlint-cli@0.45.0
Terminal window
git clone https://github.com/rshade/finfocus.git
cd finfocus
go mod download
make build
./bin/finfocus --help

Run make help for a complete list. All available targets:

TargetDescription
make buildBuild the finfocus binary to bin/finfocus
make testRun all unit tests
make test-raceRun tests with Go race detector enabled
make lintRun Go linters (golangci-lint) and Markdown linters
make validateRun go mod tidy, go vet, and format validation
make cleanRemove build artifacts (bin/ directory)
make runBuild and run binary with --help flag
make devBuild and run binary without arguments
make inspectLaunch MCP Inspector for interactive testing
TargetDescription
make docs-lintLint documentation markdown files
make docs-buildBuild documentation site with Jekyll
make docs-serveServe documentation locally (localhost:4000)
make docs-validateValidate documentation structure and completeness
Terminal window
make build # Should complete without errors
make test # All tests should pass
make lint # No linting errors
make validate # Module and vet checks pass

New features must follow specification-driven development using SpecKit. This workflow ensures features are properly designed before implementation.

  • Better planning: Features are fully specified before coding begins
  • Clearer requirements: User stories and acceptance criteria defined upfront
  • Consistent quality: Follows project constitution and quality gates
  • Easier review: Reviewers understand the intent and scope
Terminal window
uv tool install specify-cli --from git+https://github.com/github/spec-kit.git
pipx install git+https://github.com/github/spec-kit.git
  1. Create specification - Define what you’re building:

    /speckit.specify [your feature description]
  2. Clarify ambiguities - Resolve underspecified areas (recommended):

    /speckit.clarify

    This asks targeted questions to fill gaps in your spec before planning.

  3. Plan implementation - Design the technical approach:

    /speckit.plan
  4. Generate tasks - Break down into actionable items:

    /speckit.tasks
  5. Analyze consistency - Validate artifacts before implementation:

    /speckit.analyze

    This performs read-only analysis across spec, plan, and tasks to catch inconsistencies, gaps, and constitution violations.

  6. Implement - Build the feature:

    /speckit.implement

All specifications, plans, and templates are stored in the .specify/ directory:

.specify/
├── memory/
│ └── constitution.md # Project principles and quality gates
├── scripts/ # Helper scripts for SpecKit workflows
│ └── bash/
│ ├── check-prerequisites.sh
│ ├── create-new-feature.sh
│ └── setup-plan.sh
└── templates/ # Templates for specs, plans, tasks
├── spec-template.md
├── plan-template.md
├── tasks-template.md
└── checklist-template.md

Important: Review .specify/memory/constitution.md before starting any feature work. It defines the core principles and quality gates that all contributions must follow.

For minor bug fixes that don’t require SpecKit:

  1. Create a branch:

    Terminal window
    git checkout -b fix/brief-description main
  2. Make your changes and write tests

  3. Run quality checks:

    Terminal window
    make test # Must pass
    make lint # Must pass
  4. Submit a pull request with:

    • Clear description of the bug
    • Explanation of the fix
    • Tests demonstrating the fix works

All contributions must meet these quality gates, which are enforced by CI:

  • Test Coverage: Minimum 80% overall, 95% for critical paths
  • Linting: golangci-lint must pass with zero errors
  • Security: govulncheck must report no high/critical vulnerabilities
  • Formatting: All Go code must be formatted with gofmt
  • Documentation: Minimum 80% docstring coverage for exported symbols

Always run these commands before submitting:

Terminal window
make lint # Must pass with no errors
make test # All tests must pass
make validate # Module and vet checks must pass

For detailed testing instructions, see the Testing Guide.

  • Write tests before implementation (TDD approach)
  • Include tests for all new code paths
  • Test error conditions and edge cases
  • Use table-driven tests where appropriate
  • Run tests with race detector: make test-race

FinFocus uses Go’s native fuzzing (Go 1.25+) to test parser resilience:

Terminal window
go test -fuzz=FuzzJSON$ -fuzztime=30s ./internal/ingest
go test -fuzz=FuzzYAML$ -fuzztime=30s ./internal/spec
go test -fuzz=. -fuzztime=30s ./internal/ingest

Fuzz test locations:

PackageTest FunctionTarget
internal/ingestFuzzJSONJSON parser
internal/ingestFuzzPulumiPlanParseFull plan parsing
internal/specFuzzYAMLYAML spec parsing
internal/specFuzzSpecFilenameSpec filename parser

Seed corpus:

Fuzz tests use seed corpora in testdata/fuzz/ directories. Add new interesting inputs discovered during fuzzing to these directories.

CI integration:

  • PRs run 30-second fuzz smoke tests
  • Nightly builds run 6-hour deep fuzzing sessions

FinFocus includes performance benchmarks for scalability testing:

Terminal window
go test -bench=. -benchmem ./test/benchmarks/...
go test -bench=BenchmarkScale -benchmem ./test/benchmarks/...
go test -bench=BenchmarkScale1K -benchtime=10x -benchmem ./test/benchmarks/...

Available benchmarks:

BenchmarkDescriptionTarget
BenchmarkScale1K1,000 resources< 1s
BenchmarkScale10K10,000 resources< 30s
BenchmarkScale100K100,000 resources< 5min
BenchmarkDeeplyNestedDeep nesting complexity< 1s
BenchmarkJSONParsingJSON parsing at scaleBaseline
BenchmarkGeneratorOverheadGenerator overheadBaseline

Benchmark guidelines:

  • Run benchmarks on a quiet system for consistent results
  • Use -benchtime=10x for quick checks, -benchtime=1m for accurate results
  • Compare results between commits to detect performance regressions
  • CI runs smoke benchmarks (1x) on every PR

Follow Conventional Commits:

type(scope): description
[optional body]
[optional footer]

Types: feat, fix, docs, test, refactor, perf, chore

Examples:

feat(cli): add --format flag for cost output
fix(engine): correct monthly cost calculation rounding
docs(contributing): add SpecKit workflow documentation
test(registry): add plugin discovery edge case tests
  1. Ensure your branch is current:

    Terminal window
    git fetch origin
    git rebase origin/main
  2. Run all quality checks:

    Terminal window
    make test
    make lint
    make validate
  3. Push and create PR:

    Terminal window
    git push origin your-branch-name
  4. Fill in PR template with:

    • Description of changes
    • Type of change (feature, fix, docs, etc.)
    • Testing performed
    • Related issues

All pull requests must pass:

  • Go Tests with race detection
  • Code Coverage (minimum threshold)
  • golangci-lint
  • Security scanning (govulncheck)
  • Documentation validation
  • Cross-platform builds (Linux, macOS, Windows)

To assist with debugging, the project employs an automated nightly failure analysis workflow:

  • Trigger: When a nightly build fails, an issue is created with the nightly-failure label.
  • Analysis: A workflow automatically runs to fetch logs, analyze them using OpenCode, and post a triage report as a comment.
  • Goal: Provide immediate root cause hypothesis and suggested fixes to reduce manual investigation time.
  • Hardening: The workflow enforces strict security and reliability standards:
    • Pinned Dependencies: Uses specific versions of CLI tools and actions.
    • Timeouts: Enforces a 59-minute execution limit to prevent resource exhaustion.
    • Error Handling: Fails explicitly on any command error to avoid silent failures.

FinFocus operates as a three-repository ecosystem:

RepositoryPurpose
finfocusCLI tool, plugin host, orchestration engine
finfocus-specProtocol buffer definitions, SDK generation
finfocus-pluginPlugin implementations (Kubecost, Vantage)

Cross-repository changes require coordination. See the constitution for the cross-repo change protocol.

Issues labeled with decision represent deliberate architectural or product decisions with documented reasoning. These serve as lightweight Architecture Decision Records (ADRs) without the overhead of separate markdown files.

When to use decision:

  • Thorough analysis was performed
  • Reasoning is documented in the issue body
  • A deliberate choice was made (implement, defer, or reject)

Finding past decisions:

Terminal window
gh issue list --repo rshade/finfocus --state closed --label decision

Why this matters:

  • Prevents re-litigating the same issues
  • New contributors can understand why things are the way they are
  • Creates searchable institutional knowledge
LabelPurpose
decisionDeliberate architectural/product decision
enhancementNew feature or request
bugSomething isn’t working
documentationDocumentation improvements
good first issueGood for newcomers
  • GitHub Issues: Bug reports and feature requests
  • GitHub Discussions: Questions and community discussion

Be respectful and constructive in all interactions. We welcome contributors of all experience levels and backgrounds.


Thank you for contributing to FinFocus Core!