Thank you for your interest in contributing to TabSSH! We welcome contributions from everyone, whether you're fixing a typo, reporting a bug, or implementing a major feature.
- Code of Conduct
- Getting Started
- How to Contribute
- Development Setup
- Coding Guidelines
- Commit Guidelines
- Pull Request Process
- Reporting Bugs
- Suggesting Features
- Translation & Localization
- Community
This project adheres to a Code of Conduct that all contributors are expected to follow:
- Be respectful - Treat everyone with respect and kindness
- Be inclusive - Welcome newcomers and help them get started
- Be constructive - Provide helpful feedback and suggestions
- Be professional - Keep discussions focused and on-topic
- No harassment - Zero tolerance for harassment of any kind
If you experience or witness unacceptable behavior, please report it to git-admin+conduct@casjaysdev.pro.
Before you start contributing, make sure you have:
- Git - Version control
- GitHub Account - For pull requests and issues
- Development Environment - Choose one:
- Option A (Recommended): Docker 20.10+
- Option B: Android SDK 34 + JDK 17 + Gradle 8.1.1+
-
Fork the repository:
- Visit https://github.com/tabssh/android
- Click the "Fork" button in the top-right corner
-
Clone your fork:
git clone https://github.com/YOUR-USERNAME/android.git cd android -
Add upstream remote:
git remote add upstream https://github.com/tabssh/android.git
-
Keep your fork updated:
git fetch upstream git checkout main git merge upstream/main
You can contribute in many ways:
-
Code Contributions
- Fix bugs
- Implement new features
- Improve performance
- Refactor code
- Add tests
-
Documentation
- Improve README and guides
- Add code comments
- Write tutorials
- Fix typos
-
Design
- Create themes
- Design UI mockups
- Improve accessibility
- Suggest UX improvements
-
Testing
- Report bugs
- Test on different devices
- Verify bug fixes
- Test new features
-
Translation
- Translate to new languages
- Improve existing translations
- Update outdated translations
-
Community
- Help answer questions
- Review pull requests
- Participate in discussions
- Share the project
# Build Docker image
make dev
# Build debug APKs
make build
# Install to device
make install
# View logs
make logs# Install dependencies
# - Android SDK 34
# - JDK 17
# - Gradle 8.1.1+
# Build debug APKs
./gradlew assembleDebug
# Run tests
./gradlew test
# Install to device
./gradlew installDebugAndroid Studio (Recommended)
- Open Android Studio
- File → Open → Select
android/directory - Wait for Gradle sync to complete
- Configure SDK: Tools → SDK Manager → Install Android SDK 34
- Configure JDK: File → Project Structure → SDK Location → JDK 17
IntelliJ IDEA
- Open IntelliJ IDEA
- Open Project → Select
android/directory - Configure Android SDK and JDK 17
- Install Kotlin plugin if not already installed
VS Code
- Install extensions:
- Kotlin Language Support
- Android SDK Tools
- Open
android/directory - Configure paths in
.vscode/settings.json
We follow the official Kotlin Coding Conventions:
// ✅ Good
class SSHConnection(
private val hostname: String,
private val port: Int,
private val username: String
) {
fun connect(): Result<Session> {
// Implementation
}
}
// ❌ Bad
class SSHConnection(private val hostname:String,private val port:Int,private val username:String){
fun connect():Result<Session>{
// Implementation
}
}-
Indentation: 4 spaces (no tabs)
-
Line Length: 120 characters maximum
-
Naming:
- Classes:
PascalCase - Functions:
camelCase - Constants:
SCREAMING_SNAKE_CASE - Private properties:
_prefixWithUnderscore(optional)
- Classes:
-
File Organization:
- One public class per file
- File name = Class name
- Package structure follows directory structure
-
Comments:
- Use KDoc for public APIs
- Explain why, not what
- Remove commented-out code
- Keep comments up to date
/**
* Manages SSH connections with automatic reconnection and session persistence.
*
* This class handles the lifecycle of SSH connections, including:
* - Initial connection establishment
* - Authentication (password, key, keyboard-interactive)
* - Session keep-alive
* - Automatic reconnection on network changes
*
* @property hostname The SSH server hostname or IP address
* @property port The SSH server port (default: 22)
* @property username The username for authentication
*/
class SSHConnectionManager(
private val hostname: String,
private val port: Int = 22,
private val username: String
) {
/**
* Establishes an SSH connection with the configured parameters.
*
* This method will attempt to connect using the configured authentication
* method. If the connection fails, it will throw a [ConnectionException]
* with details about the failure.
*
* @return A [Result] containing the established [Session] or an error
* @throws ConnectionException if the connection cannot be established
*/
suspend fun connect(): Result<Session> {
// Implementation
}
}-
Never hardcode secrets:
// ❌ Bad val password = "mypassword123" // ✅ Good val password = securePasswordManager.getPassword(connectionId)
-
Validate all input:
// ✅ Good fun setHostname(hostname: String) { require(hostname.isNotBlank()) { "Hostname cannot be blank" } require(hostname.length <= 255) { "Hostname too long" } // Additional validation }
-
Use secure defaults:
// ✅ Good val strictHostKeyChecking = true val allowWeakCrypto = false
-
Handle sensitive data carefully:
// ✅ Good try { val password = getPassword() // Use password } finally { password.fill('\u0000') // Clear from memory }
-
Write tests for new features:
@Test fun `connect with valid credentials should succeed`() { val connection = SSHConnection("example.com", 22, "user") val result = connection.connect("password") assertTrue(result.isSuccess) }
-
Test edge cases:
@Test fun `connect with empty hostname should throw exception`() { assertThrows<IllegalArgumentException> { SSHConnection("", 22, "user") } }
-
Mock external dependencies:
@Test fun `connection failure should retry`() { val mockSession = mock<Session>() whenever(mockSession.connect()).thenThrow(IOException()) // Test retry logic }
We follow the Conventional Commits specification:
<type>(<scope>): <subject>
<body>
<footer>
- feat: New feature
- fix: Bug fix
- docs: Documentation changes
- style: Code style changes (formatting, no logic change)
- refactor: Code refactoring
- perf: Performance improvements
- test: Adding or updating tests
- build: Build system or dependency changes
- ci: CI/CD configuration changes
- chore: Other changes (maintenance, etc.)
# Feature
feat(ssh): add support for Ed25519 keys
Implemented Ed25519 key parsing and authentication.
This provides better security and performance compared to RSA.
Fixes #123
# Bug fix
fix(terminal): prevent crash on rapid tab switching
Added synchronization to tab manager to prevent race condition
when switching tabs quickly.
Fixes #456
# Documentation
docs(readme): update installation instructions
Added steps for F-Droid installation and clarified
system requirements.
# Refactoring
refactor(crypto): extract key parsing to separate class
Moved PEM key parsing logic from SSHKeyManager to
dedicated PEMKeyParser class for better separation
of concerns.- Keep commits atomic - One logical change per commit
- Write clear messages - Explain why, not what
- Reference issues - Use
Fixes #123,Closes #456,Related to #789 - Sign your commits - Use GPG signing when possible
-
Update your branch:
git fetch upstream git rebase upstream/main
-
Run tests:
./gradlew test ./gradlew lint -
Build successfully:
make build # or ./gradlew assembleDebug -
Test on device:
- Install the APK on a physical device or emulator
- Test your changes thoroughly
- Verify no regressions
-
Push your changes:
git push origin feature/your-feature-name
-
Open a pull request:
- Go to https://github.com/tabssh/android/pulls
- Click "New Pull Request"
- Select your fork and branch
- Fill out the PR template completely
- Add screenshots/videos if applicable
-
Wait for review:
- Maintainers will review your PR
- Address any feedback or requested changes
- Be patient and respectful
- Code follows style guidelines
- All tests pass
- Documentation is updated
- Commits are atomic and well-described
- PR description is complete
- Screenshots/videos added (if UI changes)
- No merge conflicts
- CI/CD pipeline passes
-
Squash commits if requested:
git rebase -i HEAD~N # N = number of commits -
Update if needed:
git push --force-with-lease
-
Celebrate! Your contribution is now part of TabSSH! 🎉
- Check existing issues: Search for duplicates
- Update to latest version: Ensure you're on the latest release
- Reproduce the bug: Can you consistently reproduce it?
- Gather information: Version, device, Android version, logs
Use the Bug Report template and include:
- Clear description of the bug
- Steps to reproduce
- Expected vs actual behavior
- Version and device information
- Logs (if available)
- Screenshots (if applicable)
# On your computer (with device connected):
adb logcat | grep TabSSH > tabssh-logs.txt
# Or use:
adb logcat -s TabSSH:V- Check existing issues and roadmap: Might already be planned
- Consider scope: Does it fit TabSSH's goals?
- Think about implementation: Is it technically feasible?
Use the Feature Request template and include:
- Clear problem statement
- Proposed solution
- Alternative solutions considered
- Use cases and examples
- Mockups or references (if applicable)
-
Create string resources:
# Copy base strings cp app/src/main/res/values/strings.xml \ app/src/main/res/values-XX/strings.xml # XX = language code (es, fr, de, etc.)
-
Translate strings:
<!-- values-es/strings.xml --> <resources> <string name="app_name">TabSSH</string> <string name="connection_title">Conexión</string> <string name="connect_button">Conectar</string> <!-- ... --> </resources>
-
Test thoroughly:
- Switch device language
- Verify all strings display correctly
- Check for truncation or layout issues
-
Submit PR:
- Include all translated strings
- Add language to README
- Note any strings that need context
- Maintain tone: Keep the friendly, professional tone
- Be concise: UI strings should be short
- Use native terms: Use terms familiar to native speakers
- Preserve placeholders: Keep %s, %d, etc. intact
- Test on device: Verify appearance in UI
- GitHub Issues: Bug reports and feature requests
- GitHub Discussions: Q&A, ideas, and general discussion
- Email: git-admin+support@casjaysdev.pro
- Twitter: @tabssh
- Matrix: #tabssh:matrix.org
- SPEC.md - Complete technical specification
- CLAUDE.md - Project tracker
- TODO.md - Development roadmap
- scripts/README.md - Build scripts documentation
- Search issues: Someone may have asked before
- Ask in discussions: Community members are helpful
- Be specific: Provide details, versions, logs
- Answer questions in discussions
- Review pull requests
- Test bug fixes
- Improve documentation
- Share the project
Contributors are recognized in:
- CHANGELOG.md: For each release
- README.md: In the acknowledgments section
- Git history: Your commits are永久 preserved
- GitHub: Contributor badge on your profile
All contributions, no matter how small, are valued and appreciated!
By contributing to TabSSH, you agree that your contributions will be licensed under the MIT License.
See LICENSE.md for details.
If you have questions about contributing:
- Open a GitHub Discussion
- Email us at git-admin+contribute@casjaysdev.pro
- Check the FAQ in README
Thank you for contributing to TabSSH! Together, we're building the best SSH client for Android. 🚀