-
Notifications
You must be signed in to change notification settings - Fork 0
Developer Guide
Complete guide for contributing to AutoCat development.
- Git with submodule support
- Android Studio (latest stable version)
- Java 21 JDK
- GitHub account
-
GitHub CLI (
gh) for releases (optional)
git clone --recursive https://github.com/thejaustin/AutoCat.git
cd AutoCatIf you forget --recursive, initialize submodules:
git submodule update --init --recursive- Open Android Studio
- File β Open β Select AutoCat directory
- Select build variant:
lawnWithQuickstepGithubDebug - Wait for Gradle sync
If you see errors with iconloaderlib or searchuilib:
git submodule update --init --recursiveALL builds are handled exclusively by GitHub Actions.
Building Android apps on Termux/mobile devices is:
- Resource-Intensive: Requires 6GB+ RAM, takes 30+ minutes, drains battery
- Unreliable: Frequent OOM crashes, Gradle daemon crashes, corrupted artifacts
- Unnecessary: GitHub Actions provides free, consistent, reproducible builds
# Edit code as needed
# Run code formatting (this is safe)
./gradlew spotlessApplygit add .
git commit -m "feat: your changes"
git push- GitHub Actions will automatically build on push
- View progress:
gh run listor check GitHub website - Build takes ~10-15 minutes on GitHub servers
# Download from latest release
gh release download dev-latest
# Or from GitHub web interface
# https://github.com/thejaustin/AutoCat/releases/tag/dev-latestβ Safe to run:
# Code formatting
./gradlew spotlessApply
./gradlew spotlessCheck
# Gradle info
./gradlew tasks
./gradlew help
./gradlew projects
# Git operations
git status
git add .
git commit -m "message"
git push
# GitHub CLI
gh run list
gh run watch
gh release list
gh release downloadβ NEVER run these:
./gradlew build # β WILL FAIL
./gradlew assembleDebug # β WILL FAIL
./gradlew assembleRelease # β WILL FAIL
./gradlew installDebug # β WILL FAIL
./gradlew bundleDebug # β WILL FAIL
./gradlew clean build # β WILL FAILWe use a tiered workflow to balance development speed with stability. All PRs target the 15-dev branch.
| Tier | Definition | Examples | Protocol |
|---|---|---|---|
| Trivial changes | Zero risk of functional regression | Fixing typos, simple code style fixes | Commit directly to 15-dev |
| Simple, self-contained work | Functionally isolated, very low risk | Single-file bug fixes, minor UX polish | 1. Create PR 2. Assign reviewer 3. Enable Auto-merge |
| Medium complexity features | Multiple components, not deeply architectural | New settings screen, new search provider | 1. Create detailed PR 2. Assign core team |
| Major architectural changes | High-risk, complex changes | Android version rebase | 1. Very detailed PR 2. Mandatory Review before merge |
We follow Conventional Commits:
Format: type(scope): subject
Example: feat(settings): Add toggle for new feature
Allowed Types:
-
feat- New feature -
fix- Bug fix -
style- Code style changes (formatting) -
refactor- Code refactoring -
perf- Performance improvements -
docs- Documentation changes -
test- Test additions/changes -
chore- Build/tooling changes
AutoCat-Specific Convention:
All commits automatically include attribution footer:
π€ Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
lawnchair/
βββ src/app/lawnchair/ # AutoCat-specific code (ADD NEW FILES HERE)
β βββ categorization/ # Categorization system
β β βββ llm/ # LLM providers
β β βββ stages/ # Categorization pipeline
β β βββ learning/ # User correction learning
β βββ data/tab/ # Database entities & DAOs
β βββ ui/preferences/ # Settings screens
β βββ preferences/ # Preference definitions
β
src/ # Launcher3 codebase (MINIMIZE CHANGES)
βββ com/android/launcher3/ # Upstream Launcher3 code
Rule: Always add new files to lawnchair/src/app/lawnchair/, not src/.
42 AutoCat Files across 5 packages:
app.lawnchair.categorization/ (19 files)
βββ AccuracyTracker.kt
βββ AdaptiveModelSelector.kt
βββ CategorizationManager.kt
βββ CategoryFolderSyncService.kt
βββ llm/
β βββ GoogleAIProvider.kt
β βββ ClaudeProvider.kt
β βββ OpenAIProvider.kt
β βββ PerplexityProvider.kt
β βββ LLMProvider.kt
β βββ ProviderCircuitBreaker.kt
β βββ ConfidenceCalibrator.kt
βββ stages/
βββ BuiltInCategorizer.kt
βββ LLMCategorizer.kt
app.lawnchair.data.tab/ (7 files)
βββ TabDatabase.kt
βββ TabDao.kt
βββ AccuracyDao.kt
βββ entities/
βββ AppTab.kt
βββ CustomTab.kt
βββ ModelAccuracy.kt
app.lawnchair.ui.preferences.destinations/ (8 files)
βββ AppCategorizationListPreferences.kt
βββ CategorizationSettingsPreferences.kt
βββ CategoryManagementPreferences.kt
βββ LLMSettingsPreferences.kt
See AutoCat vs Upstream for complete file list.
Follow Kotlin Coding Conventions:
- Use camelCase for variables/functions
- Use PascalCase for classes
- 4 spaces for indentation
- Max line length: 120 characters
- Always use explicit types for public APIs
Always run before committing:
./gradlew spotlessApplyCheck formatting:
./gradlew spotlessCheckStrings in strings.xml follow this format:
| Type | Format | Example |
|---|---|---|
| Generic word | $1 |
disagree_or_agree |
| Action | $1_action |
apply_action |
| Preference/popup label | $1_label |
folders_label |
| Preference description | $1_description |
folders_description |
| Preference choice | $1_choice |
off_choice |
| Feature string | (feature_name)_$1 |
colorpicker_hsb |
| Launcher string | $1_launcher |
device_contacts_launcher |
When changing database schema:
-
Increment version number in
TabDatabase.kt -
Add migration logic (or use
fallbackToDestructiveMigration()for dev) - Test migration with existing data
- Document changes in commit message
Example:
@Database(
entities = [AppTab::class, CustomTab::class, ModelAccuracy::class],
version = 7, // Increment this
exportSchema = false,
)When testing a feature:
- Feature works as expected
- No crashes or errors
- Settings save and persist
- Works after app restart
- No performance degradation
- UI looks correct on different screen sizes
- Logs show expected output
Use GitHub Issues template. Include:
-
Build info: Commit hash (e.g.,
AutoCat-debug-abc1234.apk) - Android version: From Settings β About Phone
- Device model: Manufacturer and model
- Steps to reproduce: Exact steps
- Expected vs actual: What should happen vs what happens
-
Logs:
adb logcat | grep AutoCat
-
Main branch:
15-dev -
Feature branches:
feature/your-feature-name -
Bug fixes:
fix/issue-number-description
-
Create branch:
git checkout -b feature/new-feature
-
Make changes and commit:
git add . git commit -m "feat: Add new feature"
-
Push to GitHub:
git push origin feature/new-feature
-
Create PR on GitHub:
- Base branch:
15-dev - Include description of changes
- Link related issues
- Enable auto-merge (for simple PRs)
- Base branch:
-
Wait for CI:
- GitHub Actions will build and test
- Fix any errors
- Get review approval
-
Merge:
- Auto-merge will merge when CI passes and reviewer approves
- Or manually merge after review
AutoCat uses Material 3 Expressive design system:
- Typography: Material 3 type scale
- Colors: Material 3 dynamic colors
- Spacing: 8dp grid system
- Components: Material 3 components
Use existing preference components:
@Composable
fun MyPreferences() {
PreferenceLayout(label = "My Settings") {
PreferenceGroup(heading = "Section 1") {
SwitchPreference(
adapter = preferenceManager.mySetting.getAdapter(),
label = "My Setting"
)
}
}
}See Preference Components README for details.
-
Create provider class in
app.lawnchair.categorization.llm/:class MyLLMProvider(context: Context) : LLMProvider { override suspend fun categorizeApp(...): CategorizationResult { // Implementation } }
-
Add to provider registry in
CategorizationManager.kt -
Add preferences in
PreferenceManager.kt:val llmMyProviderKey = StringPref("pref_llmMyProviderKey", "", {}) val llmMyProviderModel = StringPref("pref_llmMyProviderModel", "default-model", {})
-
Add UI in
LLMSettingsPreferences.kt -
Test with real API key
-
Create entity in
app.lawnchair.data.tab.entities/:@Entity(tableName = "my_table") data class MyEntity( @PrimaryKey val id: Int, @ColumnInfo(name = "field") val field: String )
-
Add to database in
TabDatabase.kt:@Database( entities = [AppTab::class, CustomTab::class, MyEntity::class], version = 7, // Increment ) -
Create DAO in
app.lawnchair.data.tab/:@Dao interface MyDao { @Query("SELECT * FROM my_table") suspend fun getAll(): List<MyEntity> }
-
Add DAO to database:
abstract fun myDao(): MyDao
Be civil and respectful. See Code of Conduct.
- Check existing documentation
- Search closed issues on GitHub
- Ask in Telegram/Discord
- Open a discussion on GitHub
- Check if issue already reported
- Test with latest build
- Create issue with all required information
- Be patient and responsive to questions
Last Updated: 2025-12-25
AutoCat | Fork of Lawnchair 15 | Download Latest Build | Last Updated: 2025-12-25