| name | add-interactor |
| description | Scaffold a new Strata interactor with interface, implementation, fake, and test |
| disable-model-invocation | true |
| argument-hint | <feature-name> <InteractorName> [--observe] |
Add Interactor
Scaffold a new Strata interactor for an existing feature module, including the public interface, implementation, fake, and test.
Input: $ARGUMENTS
Step 1: Parse Input
Extract:
- Feature name: The feature module to add the interactor to (e.g.,
summary)
- Interactor name: The name of the interactor (e.g.,
FetchUser, ObserveLastSavedValue)
- Type:
- No flag →
StrataInteractor (one-shot async, returns StrataResult<R>)
--observe → StrataSubjectInteractor (stream, exposes Flow<T> via .flow)
Verify the feature module exists at features/<feature-name>/. If it doesn't exist, stop and ask the user whether they intended a different feature name or whether they need to create the feature first with /add-feature. Do not proceed until the feature exists.
Step 2: Determine Parameters and Return Types
Ask the user:
- What are the input parameters type? (e.g.,
Int, String, Unit)
- What is the return/output type? (e.g.,
User, List<Item>, Int?)
Step 3: Read Existing Module Structure
Read the feature module's existing files to understand:
- Package naming conventions
- Existing
build.gradle.kts dependencies
- Any existing interactors to match style
Step 4: Create Files
Interface in api/
Place at: features/<feature-name>/api/src/main/java/<package>/api/<InteractorName>.kt
StrataInteractor (one-shot):
abstract class <InteractorName> : StrataInteractor<P, R>()
StrataSubjectInteractor (observe):
abstract class <InteractorName> : StrataSubjectInteractor<P, T>()
Implementation in domain/
Place at: features/<feature-name>/domain/src/main/java/<package>/domain/<InteractorName>Impl.kt
StrataInteractor (one-shot):
@ContributesBinding(AppScope::class)
class <InteractorName>Impl @Inject constructor(
) : <InteractorName>() {
override suspend fun doWork(params: P): R {
TODO("Implement")
}
}
StrataSubjectInteractor (observe):
@ContributesBinding(AppScope::class)
class <InteractorName>Impl @Inject constructor(
) : <InteractorName>() {
override fun createObservable(params: P): Flow<T> {
TODO("Implement")
}
}
Fake in test directories
Create the Fake in both src/test/ and src/androidTest/ test subpackages where test files exist for the feature (they do not share code).
Place in the consuming module's test directory under a fakes/ subpackage (e.g., <consuming-module>/src/test/java/<package>/<layer>/fakes/Fake<InteractorName>.kt). Typically this is the presentation module's test source, but use whichever module actually depends on the interactor.
StrataInteractor Fake:
class Fake<InteractorName>(
private val shouldFail: Boolean = false
) : <InteractorName>() {
val invocations = mutableListOf<P>()
override suspend fun doWork(params: P): R {
if (shouldFail) throw IllegalStateException("<InteractorName> failed for testing")
invocations.add(params)
TODO("Return test value")
}
}
StrataSubjectInteractor Fake:
class Fake<InteractorName> : <InteractorName>() {
val valueFlow = MutableStateFlow<T>()
override fun createObservable(params: P): Flow<T> = valueFlow
}
Unit Test in domain/
Place at: features/<feature-name>/domain/src/test/java/<package>/domain/<InteractorName>ImplTest.kt
class <InteractorName>ImplTest : BehaviorSpec({
Given("a <InteractorName> that succeeds") {
When("invoked with params") {
Then("it returns the expected result") {
val subject = <InteractorName>Impl()
val result = subject(params)
result.shouldBeInstanceOf<StrataResult.Success<*>>()
}
}
}
Given("a <InteractorName> that fails") {
When("invoked") {
Then("it returns Failure") {
val subject = <InteractorName>Impl()
val result = subject(params)
result.shouldBeInstanceOf<StrataResult.Failure>()
}
}
}
})
For StrataSubjectInteractor, test the flow output using Turbine:
class <InteractorName>ImplTest : BehaviorSpec({
Given("a <InteractorName>") {
When("observed") {
Then("it emits the expected values") {
val subject = <InteractorName>Impl()
subject(params)
subject.flow.test {
awaitItem() shouldBe expectedValue
}
}
}
}
})
Step 5: License Headers
All generated files MUST include the Apache 2.0 license header:
Step 6: Verify
Run ./gradlew :<feature-module>:compileDebugKotlin for the affected modules (api, domain) to verify compilation.
Report:
- Which files were created
- The interactor type (one-shot or observe)
- Parameter and return types
- Where the fake(s) were placed