We love your input! We want to make contributing to MultiGPT as easy and transparent as possible, whether it's:
- Reporting a bug
- Discussing the current state of the code
- Submitting a fix
- Proposing new features
- Becoming a maintainer
We use GitHub to host code, to track issues and feature requests, as well as accept pull requests.
Pull requests are the best way to propose changes to the codebase. We actively welcome your pull requests:
- Fork the repository and create your branch from
main. - Clone your fork locally:
git clone https://github.com/yourusername/MultiGPT.git cd MultiGPT - Set up the development environment:
- Install Android Studio Hedgehog or newer
- Open the project in Android Studio
- Let Gradle sync complete
- Create a feature branch:
git checkout -b feature/amazing-feature
- Make your changes and ensure they follow our coding standards
- Test thoroughly on different Android versions and devices
- Commit your changes with clear, descriptive messages:
git commit -m 'Add amazing feature: brief description' - Push to your fork:
git push origin feature/amazing-feature
- Create a Pull Request from your branch to our
mainbranch
- Follow Kotlin Coding Conventions
- Use meaningful variable and function names
- Add KDoc comments for public APIs
- Keep functions small and focused
- Use proper indentation (4 spaces)
- Use trailing commas in multi-line structures
- Follow Android Architecture Guidelines
- Use Jetpack Compose best practices
- Follow Material Design 3 principles
- Optimize for different screen sizes and densities
- Use proper resource naming conventions
/**
* Repository for managing AI provider configurations
*/
class AiProviderRepository @Inject constructor(
private val dataStore: DataStore<Preferences>,
private val providerDao: AiProviderDao,
) {
companion object {
private const val MAX_RETRY_COUNT = 3
}
/**
* Fetches all enabled AI providers
* @return Flow of enabled providers
*/
fun getEnabledProviders(): Flow<List<AiProvider>> {
return providerDao.getEnabledProviders()
.catch { exception ->
Logger.e("Failed to fetch providers", exception)
emit(emptyList())
}
}
}
@Composable
fun ChatMessage(
message: Message,
modifier: Modifier = Modifier,
) {
Surface(
modifier = modifier.fillMaxWidth(),
color = MaterialTheme.colorScheme.surfaceVariant,
) {
Column(
modifier = Modifier.padding(16.dp),
) {
Text(
text = message.content,
style = MaterialTheme.typography.bodyMedium,
)
}
}
}app/src/main/kotlin/com/matrix/multigpt/
├── data/ # Data layer
│ ├── local/ # Room database, DataStore
│ ├── remote/ # API services, DTOs
│ └── repository/ # Repository implementations
├── domain/ # Business logic
│ ├── model/ # Domain models
│ ├── repository/ # Repository interfaces
│ └── usecase/ # Use cases
├── presentation/ # UI layer
│ ├── ui/ # Composable screens
│ ├── viewmodel/ # ViewModels
│ └── navigation/ # Navigation logic
├── di/ # Dependency injection
└── utils/ # Utility classes
- MVVM: Use ViewModel for UI state management
- Repository Pattern: Centralize data access logic
- Use Cases: Encapsulate business logic
- Dependency Injection: Use Hilt for DI
- Single Activity: Navigate with Jetpack Navigation
- Write unit tests for ViewModels and repositories
- Add integration tests for critical flows
- Test on different Android versions (API 26+)
- Test with different AI providers
- Verify UI responsiveness and accessibility
# Run unit tests
./gradlew test
# Run instrumented tests
./gradlew connectedAndroidTest
# Run all tests with coverage
./gradlew jacocoTestReport@Test
fun `getAiProviders returns enabled providers only`() = runTest {
// Given
val providers = listOf(
AiProvider(id = "openai", isEnabled = true),
AiProvider(id = "claude", isEnabled = false),
)
coEvery { providerDao.getAllProviders() } returns flowOf(providers)
// When
val result = repository.getEnabledProviders().first()
// Then
assertEquals(1, result.size)
assertEquals("openai", result.first().id)
}We use GitHub Issues to track bugs. Report a bug by opening a new issue.
Great Bug Reports tend to have:
- A quick summary and/or background
- Steps to reproduce (be specific!)
- Sample code if applicable
- What you expected would happen
- What actually happens
- Device information (Android version, device model)
- App version
- Screenshots or screen recordings
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Tap on '....'
3. See error
**Expected behavior**
What you expected to happen.
**Device Information:**
- Device: [e.g. Samsung Galaxy S23]
- OS: [e.g. Android 14]
- App Version: [e.g. v1.2.0]
- AI Provider: [e.g. OpenAI, Claude]
**Additional context**
Screenshots, logs, or other relevant information.We also use GitHub Issues for feature requests. You can request a feature.
Great Feature Requests include:
- Clear problem description
- Proposed solution
- Alternative solutions considered
- Use cases and benefits
- Mockups or examples (if applicable)
When adding support for a new AI provider:
- Create the API client in
data/remote/ - Add data models for requests/responses
- Implement repository with proper error handling
- Add UI configuration for API keys/settings
- Write comprehensive tests
- Update documentation
@Serializable
data class NewProviderRequest(
val model: String,
val messages: List<Message>,
val temperature: Double = 1.0,
)
interface NewProviderApi {
@POST("chat/completions")
suspend fun createCompletion(
@Body request: NewProviderRequest,
): NewProviderResponse
}- Never commit API keys or sensitive data
- Validate all user inputs before API calls
- Use secure storage for API keys (EncryptedSharedPreferences)
- Handle network errors gracefully
- Implement rate limiting to prevent abuse
- Follow OWASP Mobile Security guidelines
- Update README.md for new features
- Add KDoc comments for public APIs
- Include code examples in complex implementations
- Document API integration steps
- Update CHANGELOG.md
/**
* Manages chat conversations with multiple AI providers
*
* @param providers List of enabled AI providers
* @param chatRepository Repository for chat persistence
*
* Example usage:
* ```
* val chatManager = ChatManager(providers, repository)
* val response = chatManager.sendMessage("Hello", listOf("openai", "claude"))
* ```
*/
class ChatManager(
private val providers: List<AiProvider>,
private val chatRepository: ChatRepository,
) {
// Implementation
}All submissions require review before merging:
- Automated checks must pass (build, tests, linting)
- Manual review by maintainers focuses on:
- Code quality and architecture
- Security considerations
- Performance impact
- User experience
- Documentation completeness
- Be respectful and inclusive
- Help others learn and grow
- Follow our Code of Conduct
- Join discussions in issues and pull requests
- Share knowledge and best practices
- Android Studio Hedgehog (2023.1.1) or newer
- Android SDK 34+ (API level 34)
- Kotlin 1.9+
- JDK 17+
- Git
- Clone the repository
- Open in Android Studio
- Let Gradle sync complete
- Build and run on device/emulator
- Start contributing!
For testing, you may want to add API keys to local.properties:
OPENAI_API_KEY=your_key_here
ANTHROPIC_API_KEY=your_key_here
# These are for testing only - never commit real keys!- Major.Minor.Patch (e.g., 1.2.3)
- Major: Breaking changes or major features
- Minor: New features, backward compatible
- Patch: Bug fixes and small improvements
- All tests pass
- Version number updated
- CHANGELOG.md updated
- Play Store metadata updated
- Screenshots updated if needed
- Release notes written
Contributors will be recognized in:
- README.md contributors section
- Release notes for significant contributions
- GitHub contributors page
- Special mentions in app credits
Feel free to:
- Open a discussion issue
- Join GitHub Discussions
- Contact the maintainers
- Review existing documentation
Thank you for contributing to MultiGPT! 🤖✨