Skip to content

Contributing

Getting Started

  1. Fork and clone the repository:
Terminal window
git clone https://github.com/YOUR_USERNAME/grepai.git
cd grepai
  1. Install dependencies:
Terminal window
go mod download
  1. Run tests:
Terminal window
make test
  1. Build:
Terminal window
make build

Development Commands

Terminal window
# Build the binary
make build
# Run tests with race detection
make test
# Run tests with coverage
make test-cover
# Format code with gofmt
make fmt
# Lint with golangci-lint
make lint
# Run ALL checks before committing (recommended)
make pre-commit
# Build and run
make run
# Cross-compile for all platforms
make build-all
# Generate CLI documentation
make docs-generate

Before Committing

Always run the pre-commit checks before pushing your changes:

Terminal window
make pre-commit

This single command will:

  1. Format all Go files with gofmt
  2. Vet - detect common errors with go vet
  3. Lint - run comprehensive checks with golangci-lint
  4. Test - run all tests with race detection

If all checks pass, you’re ready to commit!

Project Structure

grepai/
├── cli/ # CLI commands (Cobra)
│ ├── root.go
│ ├── init.go
│ ├── watch.go
│ ├── search.go
│ └── status.go
├── config/ # Configuration loading
├── embedder/ # Embedding providers
│ ├── embedder.go # Interface
│ ├── ollama.go
│ └── openai.go
├── store/ # Vector storage
│ ├── store.go # Interface
│ ├── gob.go
│ └── postgres.go
├── indexer/ # Indexing logic
│ ├── scanner.go # File walking
│ ├── chunker.go # Text splitting
│ └── indexer.go # Orchestration
├── search/ # Search logic
├── watcher/ # File watching
└── docs/ # Documentation (Astro/Starlight)

Adding a New Embedder

  1. Create a new file in embedder/:
embedder/myembedder.go
package embedder
type MyEmbedder struct {
// ...
}
func NewMyEmbedder(config Config) (*MyEmbedder, error) {
// ...
}
func (e *MyEmbedder) Embed(ctx context.Context, text string) ([]float32, error) {
// ...
}
func (e *MyEmbedder) EmbedBatch(ctx context.Context, texts []string) ([][]float32, error) {
// ...
}
func (e *MyEmbedder) Dimensions() int {
return 768 // or whatever your embedder produces
}
  1. Add configuration in config/config.go

  2. Wire it up in CLI commands

Adding a New Store

  1. Create a new file in store/:
store/mystore.go
package store
type MyStore struct {
// ...
}
func NewMyStore(config Config) (*MyStore, error) {
// ...
}
func (s *MyStore) Store(ctx context.Context, chunks []Chunk) error {
// ...
}
func (s *MyStore) Search(ctx context.Context, embedding []float32, limit int) ([]Result, error) {
// ...
}
func (s *MyStore) Delete(ctx context.Context, filePath string) error {
// ...
}
func (s *MyStore) Close() error {
// ...
}
  1. Add configuration in config/config.go

  2. Wire it up in CLI commands

Commit Convention

Follow conventional commits:

type(scope): description
Types: feat, fix, docs, style, refactor, test, chore

Examples:

feat(embedder): add support for Cohere embeddings
fix(watcher): handle symlink loops gracefully
docs(readme): update installation instructions

Pull Request Process

  1. Create a feature branch:
Terminal window
git checkout -b feat/my-feature
  1. Make your changes and commit

  2. Run pre-commit checks:

Terminal window
make pre-commit
  1. Push and create a PR:
Terminal window
git push origin feat/my-feature
  1. Fill out the PR template

Code Style

  • Follow standard Go conventions
  • Run make lint before committing
  • Keep functions focused and small
  • Add tests for new functionality
  • Document exported types and functions