AI-Powered Go Test Generation Engine with Closed-Loop Feedback
Status: Active Prototype
Ostinato Rigore - Persistent Rigor in Test Generation
GopherChill is a deterministic, AI-powered test generation tool for Go that solves the hallucination problem with strict intent-based specifications, signature validation, and closed-loop feedback.
Unlike other test generators that guess what to test, GopherChill:
- ✅ Extracts ALL functions (exported and unexported) with full signatures
- ✅ Parses code comments/documentation for context
- ✅ Validates generated intents match function signatures exactly
- ✅ Replaces invalid/empty existing intent files automatically
- ✅ Generates tests and runs them automatically
- ✅ Retries with LLM correction when tests fail (closed-loop)
- ✅ Stops on non-retryable errors with clear messages
| Feature | Description |
|---|---|
| Strict Intent Validation | Every package must have valid intent.md with structured test specs |
| Signature Validation | Generated intents validated against actual function signatures |
| Comment Parsing | Extracts and uses code documentation for better understanding |
| Closed-Loop Generation | Tests generated, run, and auto-corrected until they pass |
| Intent File Generator | LLM drafts intent.md from existing code with full context |
| Diff-Based Testing | Generate tests only for changed functions since last commit |
| API Error Handling | Clear messages for rate limits, invalid keys, network issues |
| Package-Level Control | Skip packages without valid intent files |
| Interactive Refactoring | LLM-powered planning with user approval workflow |
# Plan refactoring changes with interactive review
gopherchill plan -provider=mistral ./pkg/...
# Process all packages recursively
gopherchill plan -provider=mistral -recursive ./pkg/...
# Auto-approve changes (CI/CD mode)
gopherchill plan -provider=mistral -auto-approve ./pkg/...What it does:
- 🔍 Analyzes code for untestable patterns (concrete dependencies, global state, etc.)
- 🤖 LLM-powered suggestions for making code testable
- 🎯 Interactive diff review - accept, skip, or quit for each change
- 🛡️ Build validation - ensures all changes compile successfully
- 📊 Cross-package awareness - identifies impact on other packages
Example workflow:
1. LLM analyzes code → finds untestable patterns
2. Suggests refactoring → extract interfaces, inject dependencies
3. Shows interactive diff → user reviews each change
4. Applies accepted changes → validates build
5. Ready for test generation → run generate-intents and apply
gopherchill generate-intents -provider=mistral ./pkg/...What's different:
- ✅ Extracts complete function signatures (params, results, variadic)
- ✅ Parses code comments and documentation for context
- ✅ Validates existing intent files - replaces empty/invalid ones
- ✅ Validates LLM output - ensures inputs match parameter types
- ✅ Type-aware generation - appropriate defaults for int, string, bool, etc.
- ✅ Fallback mechanism - safe signature-based generation if LLM fails
Example generated intent:
## Function: Add
**Description:** Test the Add function
<!-- Signature: func(a int, b int) int -->
<!-- Original documentation:
Add adds two integers together and returns their sum.
Handles overflow by returning max int.
-->
### Test Cases:
- name: should add positive numbers
description: Adding two positive integers returns their sum
inputs: ["2", "3"] # Validated: matches 2 int params
expected: "5"# See what changed
gopherchill diff
# Generate tests for changed code only
gopherchill diff-apply -provider=mistral ./pkg/...- Analyzes git diff to find modified functions
- Faster CI - only test what changed
- Perfect for pre-commit hooks and PR reviews
git clone https://github.com/yourusername/gopherchill.git
cd gopherchill
go build ./cmd/gopherchillcp gopherchill $(go env GOPATH)/bin/# LLM drafts intent files with full signature validation
gopherchill generate-intents -provider=mistral ./pkg/...
# Review generated intents (includes signatures and docs)
# Edit test cases as needed# Apply intents and generate tests with retry logic
gopherchill apply -provider=mistral ./pkg/...# See what functions changed
gopherchill diff
# Generate tests only for changed functions
gopherchill diff-apply -provider=mistral ./pkg/...| Command | Description | LLM Required |
|---|---|---|
scan |
Scan for missing tests and untestable patterns | ❌ No |
plan |
Interactive LLM-guided refactoring planning with user approval | ✅ Yes |
generate-intents |
Generate intent.md files with signature validation |
✅ Yes |
diff |
Show changed functions since last commit | ❌ No |
diff-apply |
Generate tests for changed functions only | ✅ Yes |
apply |
Apply plan and generate tests (closed-loop) | ✅ Yes |
ci |
Full CI pipeline | ✅ Yes |
The plan command has been enhanced with:
- Interactive review - See diffs before accepting changes
- LLM-powered analysis - Intelligent detection of untestable patterns
- Cross-package awareness - Knows about references in other files
- Build validation - Ensures all changes compile
- Auto-approve mode - For CI/CD pipelines
# Interactive planning (default)
gopherchill plan -provider=mistral ./pkg/calculator
# Recursive (all packages)
gopherchill plan -provider=mistral -recursive ./pkg/...
# Auto-approve (CI/CD)
gopherchill plan -provider=mistral -auto-approve ./pkg/...# Test Intent Specification
## Function: Add
**Description:** Test the Add function that adds two integers together.
<!-- Signature: func(a int, b int) int -->
### Test Cases:
- name: should add positive numbers
description: Adding two positive integers returns their sum
inputs: ["2", "3"]
expected: "5"
- name: should handle zero
description: Adding zero to any number returns that number
inputs: ["0", "42"]
expected: "42"
---
## Method: Divide
**Receiver:** Calculator
**Description:** Test the Divide method with error handling.
<!-- Signature: func(c *Calculator, divisor int) (int, error) -->
### Test Cases:
- name: should divide successfully
description: Dividing 10 by 2 returns 5
inputs: ["2"]
expected: "5"
- name: should error on division by zero
description: Dividing by zero returns an error
inputs: ["0"]
expected: "error returned"
should_fail: trueEvery intent MUST have:
## Function:or## Method:header**Description:**field### Test Cases:section with at least one test case- Each test case:
name,description,expected
<!-- Signature: ... -->- Auto-added by generator for validation<!-- Original documentation: ... -->- Preserved code comments**Receiver:**- For methods (struct type)inputs:- Function arguments as JSON array (validated against signature)should_fail: true- For error test cases
| Provider | Environment Variable | Get Key |
|---|---|---|
| Mistral | MISTRAL_API_KEY |
console.mistral.ai |
| OpenAI | OPENAI_API_KEY |
platform.openai.com |
| Anthropic | ANTHROPIC_API_KEY |
console.anthropic.com |
GEMINI_API_KEY |
makersuite.google.com | |
| Ollama | None (local) | ollama.ai |
gopherchill scan ./pkg/...=== GopherChill Scan Report ===
Directory: ./pkg
Files Scanned: 10
Exported Functions: 45
Functions Missing Tests: 28
Untestable Patterns: 3
gopherchill generate-intents -provider=mistral ./newpkg/=== Generating Intent Files ===
✓ Generated: newpkg/intent.md (5 functions)
- Add func(a int, b int) int
- Subtract func(a int, b int) int
- Divide (Calculator) func(c *Calculator, divisor int) (int, error)
Please review and edit the intent file before running tests.
Pay attention to:
1. Input values match parameter types
2. Expected results are correct
3. Edge cases are covered
Run 'gopherchill apply' when ready.
# If existing intent.md is empty or invalid:
gopherchill generate-intents -provider=mistral ./pkg/Replacing invalid/empty intent file: pkg/intent.md (no function/method declarations)
✓ Generated: pkg/intent.md (3 functions)
gopherchill diff -all=== Changed Functions ===
📦 pkg/calculator
New functions:
✨ Divide (Calculator)
Modified functions:
🔄 Add (+5/-2 lines)
🔄 Subtract (Calculator) (+10/-0 lines)
Total: 3 function(s) changed in 1 package(s)
gopherchill ci -provider=mistral -max-iter=3 ./pkg/...#!/bin/bash
# .git/hooks/pre-commit
# Generate tests for staged changes
gopherchill diff-apply -provider=mistral -staged ./...
# Run tests
go test ./...name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.21"
- name: Install GopherChill
run: |
go build ./cmd/gopherchill
mv gopherchill $GOPATH/bin/
- name: Generate tests for changed code
env:
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
run: |
gopherchill diff-apply -provider=mistral ./...
- name: Run tests
run: go test ./... -race -coverprofile=coverage.out
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
files: ./coverage.out# Step 1: Generate intents from existing code (with signatures)
gopherchill generate-intents -provider=mistral ./legacy/...
# Step 2: Review generated intents
# - Check signatures match
# - Verify documentation preserved
# - Add edge cases
# Step 3: Generate tests (closed-loop)
gopherchill apply -provider=mistral ./legacy/...
# Step 4: Run full CI to validate
gopherchill ci -provider=mistral ./legacy/...Most AI test generators:
- ❌ Guess what to test (hallucination)
- ❌ Generate once, hope for the best
- ❌ No validation of test quality
- ❌ Generic error messages
- ❌ Ignore function signatures
- ❌ Don't read code comments
- ✅ Explicit specs - You define what to test via
intent.md - ✅ Signature validation - Inputs must match parameter types
- ✅ Comment parsing - Uses documentation for context
- ✅ Closed-loop - Auto-retry with LLM correction until tests pass
- ✅ Strict validation - Invalid/empty intents replaced automatically
- ✅ Clear errors - "Invalid API key", "Rate limit exceeded", etc.
- ✅ Type-aware - Appropriate defaults for each Go type
| Tool | Intent-Based | Signature Validation | Comment Parsing | Closed-Loop | Diff-Based | Error Handling |
|---|---|---|---|---|---|---|
| GopherChill | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Detailed |
| Copilot | ❌ No | ❌ No | ❌ No | ❌ No | ❌ No | |
| Cursor | ❌ No | ❌ No | ❌ No | ❌ No | ❌ No | |
| testify | ❌ Manual | ❌ N/A | ❌ N/A | ❌ N/A | ❌ No | N/A |
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests:
go test ./... - Submit a pull request
MIT License - see LICENSE for details.
- Inspired by the need for deterministic AI-generated tests
- Built with the Go programming language
- Uses LLM providers: Mistral, OpenAI, Anthropic, Google
- Ostinato Rigore - Persistent rigor in everything we do