Thank you for your interest in contributing to Construct! This document provides guidelines and information to help you contribute effectively to the project.
- Getting Started
- Development Setup
- Project Structure
- Development Workflow
- Coding Standards
- Testing
- Submitting Changes
- Reporting Issues
- Community
Before you begin contributing, ensure you have:
- Go 1.24+ installed
- Git for version control
- A GitHub account
- Familiarity with Go and basic command-line tools
- An Anthropic API key for testing
-
Fork the repository on GitHub
-
Clone your fork locally:
git clone https://github.com/YOUR_USERNAME/construct.git cd construct -
Add the upstream remote:
git remote add upstream https://github.com/furisto/construct.git
-
Install development dependencies (if any):
# The project uses Go modules, so dependencies are managed automatically go mod download
Construct uses a Go workspace with multiple modules. To build the CLI:
# Build the CLI
cd frontend/cli
go build -o construct
# Optionally install it locally for testing
sudo mv construct /usr/local/bin/construct-
Install the daemon:
construct daemon install
-
Configure a test provider:
export ANTHROPIC_API_KEY="your-test-api-key" construct modelprovider create test-provider --type anthropic
# Run all tests
go test ./...
# Run tests with coverage
go test -cover ./...
# Run tests for a specific package
go test ./backend/agent/...The project uses .golangci.yml for linting configuration:
# Install golangci-lint if you haven't already
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# Run the linter
golangci-lint run
# Run with auto-fix where possible
golangci-lint run --fixConstruct follows a modular architecture with clear separation of concerns:
construct/
├── api/ # Protocol Buffer definitions (ConnectRPC)
├── backend/ # Core backend logic
│ ├── agent/ # Agent runtime and execution
│ ├── analytics/ # Metrics and analytics
│ ├── api/ # API implementation (ConnectRPC handlers)
│ ├── event/ # Event system
│ ├── memory/ # Conversation memory and storage
│ ├── model/ # LLM Provider integration
│ ├── prompt/ # Agent prompts
│ ├── secret/ # Secret/credential management
│ └── tool/ # Tool implementations (file ops, commands, etc.)
├── frontend/
│ └──cli/ # Command-line interface
├── shared/ # Shared utilities and types
├── docs/ # Documentation
└── dev/ # Development tools and scripts
- Backend: Contains the daemon logic, agent runtime, model providers, and tool execution
- Frontend/CLI: User-facing command-line interface
- API: ConnectRPC protocol definitions for client-daemon communication
- Shared: Common types and utilities used across modules
We follow a standard Git workflow:
- main branch: Stable, production-ready code
- Feature branches: Named
feature/descriptionorfix/issue-number - Pull requests: All changes must go through PR review
-
Create a feature branch:
git checkout -b feature/my-new-feature
-
Make your changes
-
Test your changes thoroughly:
go test ./... golangci-lint run -
Commit your changes with clear, descriptive messages:
git add . git commit -m "Add feature: description of what you did"
-
Keep your branch up to date:
git fetch upstream git rebase upstream/main
-
Push to your fork:
git push origin feature/my-new-feature
Write clear, concise commit messages that explain why the change was made, not just what changed:
Good:
Add timeout handling to prevent hung tool executionsFix race condition in agent message processingRefactor model provider interface for better extensibility
Avoid:
Update codeFix bugChanges
Follow the official Go Code Review Comments and Effective Go.
Key principles:
-
Formatting: Use
gofmtorgoimports(enforced by CI) -
Naming: Use clear, descriptive names following Go conventions
- Interfaces:
Reader,Writer,AgentExecutor - Variables: camelCase for local, PascalCase for exported
- Constants: PascalCase or ALL_CAPS for exported constants
- Interfaces:
-
Error Handling: Always handle errors explicitly, never ignore them
// Good result, err := someFunction() if err != nil { return fmt.Errorf("failed to execute: %w", err) } // Bad result, _ := someFunction()
-
Testing:
- Write table-driven tests where appropriate
- Test both success and error cases
- Use descriptive test names:
TestAgentExecute_WithTimeout_ReturnsError
Before submitting a PR, ensure:
- Code follows Go style guidelines
- All tests pass (
go test ./...) - Linting passes (
golangci-lint run) - New features have tests
- Documentation is updated (if applicable)
- Commit messages are clear and descriptive
- No sensitive information (API keys, credentials) is committed
func TestAgentCreate(t *testing.T) {
tests := []struct {
name string
input *AgentInput
want *Agent
wantErr bool
}{
{
name: "valid agent creation",
input: &AgentInput{
Name: "test-agent",
Model: "test-model",
Prompt: "You are a test assistant",
},
want: &Agent{
Name: "test-agent",
Model: "test-model",
Prompt: "You are a test assistant",
},
wantErr: false,
},
{
name: "missing required field",
input: &AgentInput{
Name: "test-agent",
// Model is missing
},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := CreateAgent(tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("CreateAgent() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("CreateAgent() = %v, want %v", got, tt.want)
}
})
}
}-
Ensure your PR:
- Has a clear, descriptive title
- References any related issues
- Includes a description of what changed and why
- Passes all CI checks
- Has been rebased on the latest
mainbranch
-
PR Description Template:
## Description Brief description of what this PR does. ## Motivation Why is this change needed? What problem does it solve? ## Changes - List of specific changes made - Can be bullet points ## Testing How was this tested? What tests were added? ## Checklist - [ ] Tests pass locally - [ ] Linting passes - [ ] Documentation updated (if needed) - [ ] Breaking changes documented (if any)
-
Review Process:
- A maintainer will review your PR
- Address any feedback or requested changes
- Once approved, a maintainer will merge your PR
- Initial Review: Usually within 2-3 business days
- Feedback: We aim to provide constructive, actionable feedback
- Iteration: Be prepared to make changes based on review comments
- Merge: Once approved and CI passes, your PR will be merged
When reporting bugs, please include:
- Clear title describing the issue
- Steps to reproduce the bug
- Expected behavior vs actual behavior
- Environment details:
- OS and version
- Go version
- Construct version
- Model provider used
- Relevant logs or error messages
- Screenshots (if applicable)
Use the bug report template.
When requesting features:
- Describe the feature clearly
- Explain the use case and problem it solves
- Provide examples of how it would be used
- Suggest implementation (optional, but helpful)
Use the feature request template.
Do not open public issues for security vulnerabilities. Instead:
- Email security concerns to the maintainers
- Provide detailed information about the vulnerability
- Allow time for a fix before public disclosure
- Documentation: Check docs/ for guides and references
- GitHub Discussions: Ask questions and share ideas
- GitHub Issues: Report bugs and request features
You don't have to write code to contribute! Here are other ways to help:
- Documentation: Improve guides, add examples, fix typos
- Bug Reports: Report issues you encounter
- Testing: Test new features and provide feedback
- Feature Ideas: Suggest improvements and new capabilities
- Code Review: Review pull requests from other contributors
- Community Support: Help answer questions in discussions
We value all contributions! Contributors will be:
- Listed in release notes for significant contributions
- Credited in commit messages when appropriate
- Acknowledged in the project README (for major contributions)
# Run daemon in foreground for debugging
construct daemon run --listen-unix /tmp/construct.sock
# View daemon logs (Linux)
journalctl --user -u construct -f
# View daemon logs (macOS)
tail -f ~/Library/Logs/construct.log
# Clean build artifacts
go clean -cache
rm -rf ~/.construct/test-*
# Update dependencies
go get -u ./...
go mod tidy-
Enable verbose logging:
construct -v <command>
-
Run daemon in foreground:
construct daemon run --listen-unix
# CPU profiling
go test -cpuprofile=cpu.prof -bench=. ./backend/agent
# Memory profiling
go test -memprofile=mem.prof -bench=. ./backend/agent
# Analyze profiles
go tool pprof cpu.profBy contributing to Construct, you agree that your contributions will be licensed under the project's license.