Install
$ agentstack add skill-josephsanjaya-skills-dagger-hilt-expert ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Dagger & Hilt Expert
Expert guidance for professional Dagger and Hilt dependency injection in Android applications using KSP and modern best practices.
Provide precise, compile-time safe, and high-performance dependency injection advice. When assisting developers with Hilt, prioritize constructor injection, compile-time safety, proper scoping, and optimized test builds.
Core Principles
- Constructor Injection First: Prefer
@Inject constructorover modules when possible. - @Binds Over @Provides: Use
@Bindsfor interface bindings to optimize class generation and startup. - Narrow Scoping: Only scope when necessary (state, expensive creation, synchronization). Feature-specific dependencies must not be
@Singleton. - Single-Purpose Modules: Keep modules focused on one functional area (` for non-critical startup dependencies to prevent app cold-start lag.
Version and Gradle Configuration
Hilt projects should use Kotlin Symbol Processing (KSP) and the latest stable Hilt version (currently 2.59.2).
// build.gradle.kts (Module level)
plugins {
id("com.google.devtools.ksp")
id("com.google.dagger.hilt.android")
}
dependencies {
implementation("com.google.dagger:hilt-android:2.59.2")
ksp("com.google.dagger:hilt-compiler:2.59.2")
// For tests
testImplementation("com.google.dagger:hilt-android-testing:2.59.2")
kspTest("com.google.dagger:hilt-compiler:2.59.2")
androidTestImplementation("com.google.dagger:hilt-android-testing:2.59.2")
kspAndroidTest("com.google.dagger:hilt-compiler:2.59.2")
}
Quick Reference
Scope Selection
SingletonComponent (Annotation: @Singleton)
↓ (survives config changes)
ActivityRetainedComponent (Annotation: @ActivityRetainedScoped)
↓ (per ViewModel)
ViewModelComponent (Annotation: @ViewModelScoped)
↓ (per Activity)
ActivityComponent (Annotation: @ActivityScoped)
↓ (per Fragment)
FragmentComponent (Annotation: @FragmentScoped)
Use the narrowest scope possible. Do not scope stateless/cheap objects.
Provision Method Selection Decision Tree
Do you own the class constructor?
├─ YES → Is it an interface binding?
│ ├─ YES → Use @Binds on an interface module
│ └─ NO → Use @Inject constructor on the class
└─ NO → Use @Provides on a static object/companion module
Common Patterns
Pattern: Network Module (Static @Provides)
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideOkHttp(): OkHttpClient = OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.build()
@Provides
@Singleton
fun provideRetrofit(okHttp: OkHttpClient): Retrofit = Retrofit.Builder()
.client(okHttp)
.baseUrl("https://api.example.com")
.addConverterFactory(GsonConverterFactory.create())
.build()
}
Pattern: Repository Binding (@Binds)
interface UserRepository {
suspend fun getUser(id: String): User
}
class UserRepositoryImpl @Inject constructor(
private val api: UserApi,
private val cache: UserCache
) : UserRepository {
override suspend fun getUser(id: String): User =
cache.get(id) ?: api.fetchUser(id).also { cache.put(id, it) }
}
@Module
@InstallIn(SingletonComponent::class)
interface RepositoryModule {
@Binds
@Singleton
fun bindUserRepository(impl: UserRepositoryImpl): UserRepository
}
Pattern: Lazy Initialization
@HiltAndroidApp
class MyApplication : Application() {
@Inject lateinit var analytics: Lazy
@Inject lateinit var crashReporter: Lazy
override fun onCreate() {
super.onCreate()
crashReporter.get().initialize() // Critical only
// Defer non-critical startup dependency to background thread
CoroutineScope(Dispatchers.Default).launch {
analytics.get().initialize()
}
}
}
Pattern: Assisted Injection
class DetailViewModel @AssistedInject constructor(
private val repository: Repository,
@Assisted private val itemId: String
) : ViewModel() {
@AssistedFactory
interface Factory {
fun create(itemId: String): DetailViewModel
}
}
// Usage in Fragment
@AndroidEntryPoint
class DetailFragment : Fragment() {
@Inject lateinit var factory: DetailViewModel.Factory
private val viewModel by lazy {
factory.create(requireArguments().getString("itemId")!!)
}
}
Pattern: WorkManager Custom Initialization
WorkManager requires custom initialization with HiltWorkerFactory to inject dependencies into @HiltWorker classes. You MUST implement Configuration.Provider on the Application and disable the default WorkManagerInitializer in the manifest.
@HiltWorker
class SyncWorker @AssistedInject constructor(
@Assisted context: Context,
@Assisted params: WorkerParameters,
private val repository: SyncRepository
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result = try {
repository.sync()
Result.success()
} catch (e: Exception) {
Result.retry()
}
}
Anti-Patterns to Avoid
❌ Monolithic Module
Keep modules single-purpose. Split large modules (e.g., AppModule) into NetworkModule, DatabaseModule, AnalyticsModule.
❌ Feature-Specific Singleton
Do not put feature-specific state (e.g. OnboardingManager) in @Singleton as it causes memory leaks. Use @ActivityScoped or @ViewModelScoped.
❌ Non-Static @Provides
@Module
class NetworkModule { // ❌ Class causes instance overhead
@Provides fun provideGson(): Gson = Gson()
}
Fix: Use object and @Provides or interface and @Binds.
❌ @Provides for Simple Binding
@Provides fun provideRepo(impl: RepositoryImpl): Repository = impl // ❌ Inefficient
Fix: Use @Binds on an interface module.
Detailed References
For deep dives into architectural setups and patterns, read:
- [module-organization.md](references/module-organization.md): Single-purpose modules, visibility patterns, multi-module architecture, internal module trick.
- [scoping-strategies.md](references/scoping-strategies.md): Component hierarchy, scope selection, lifecycle management, memory optimization.
- [provides-vs-binds.md](references/provides-vs-binds.md): Performance comparison, when to use each, static vs instance methods, qualifiers.
- [testing-patterns.md](references/testing-patterns.md): @TestInstallIn, @BindValue, @UninstallModules, fakes vs mocks, build optimization.
- [performance-optimization.md](references/performance-optimization.md): Lazy injection, startup profiling, async initialization, memory management.
- [assisted-injection.md](references/assisted-injection.md): Runtime parameters, WorkManager, SavedStateHandle, factory patterns.
Scripts
- analyze_modules.py: Detects monolithic modules, non-static
@Provides, and incorrect binding usage.
python scripts/analyze_modules.py
- generatemoduletemplate.sh: Generates template for provides/binds modules.
./scripts/generate_module_template.sh
- Developers must always recommend Constructor Injection over modules, unless dependencies are interfaces or external classes.
- You should never scope stateless dependencies. Explain that scoping only introduces DoubleCheck overhead.
- WorkManager Hilt integration requires implementing
Configuration.Provideron the custom HiltApplicationclass and disabling the default WorkManager initializer viaAndroidManifest.xml(otherwise, a crash will occur). - For test environments, you must emphasize the build performance impact of
@UninstallModulesand recommend@TestInstallInfor global replacements to optimize build times. - If the session gets long or slow, suggest
/clearor/compactto prevent context decay.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: JosephSanjaya
- Source: JosephSanjaya/skills
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.