modify-feature
Skill56 starsChanged 3 months agoMITView on GitHub
Modify existing KMP features with spec-first workflow. Invoke with /modify-feature.
We split this skill into the rules it gives an agent
25 rules. About 0 are common, 15 are distinctive, and 10 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈15
Distinctive · estimate
This author's own choices. Worth a look.
10
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 14
Before editing any feature files, activate the skill marker so the PreToolUse hook allows edits:
- Distinctive: line 18
After completion (or on any early exit), remove it:
- Distinctive: line 34
If missing, stop and instruct the user:
- Very specific: line 41
Do NOT auto-invoke /audit-spec — skills do not call each other.
- Distinctive: line 45
Check for a Stitch design blueprint:
- Distinctive: line 57
If entering design-aware mode, log:
- Distinctive: line 64
Read spec sections: Requirements, Architecture, State Management, Navigation
- Distinctive: line 104
Follow patterns from @../_shared/patterns.md
- Very specific: line 110
Platform capability / native view (Rule 14): when the change adds a device capability or native view, follow …
- Very specific: line 113
Update build.gradle.kts per-platform deps (build-gradle-template → "Platform-specific dependencies").
- Very specific: line 119
UI file layout (strict allowlist): when adding or moving composables, respect the rules in @../_shared/patterns.md ("UI File Organization"):
- Very specific: line 121
Every other composable, including {Feature}Content, lives one-per-file under presentation/ui/components/
- Distinctive: line 124
Previews (mandatory for new components): when this modification adds a new component, you must also:
- Distinctive: line 131
If either is missing, add it as part of this modification.
- Distinctive: line 143
Never ask the user. Never skip.
- Distinctive: line 145
Design-aware branch: If in design-aware mode, implement in this order:
- Very specific: line 160
Default parameter values that differ from what the blueprint intends (e.g.
- Distinctive: line 175
All XTheme missing roles added to BOTH schemes
- Very specific: line 177
Every text node uses a MaterialTheme.typography.{role} — no raw fontSize/fontWeight except recorded overrides
- Distinctive: line 178
Every component in blueprint exists in implementation
- Distinctive: line 179
Every Modifier in blueprint is present in code
- Very specific: line 180
All colors use MaterialTheme.colorScheme.{role} — no raw Color() hex
- Very specific: line 182
Every images.json bundled image rendered via painterResource.
- Very specific: line 183
Every ## Motion row implemented in a motion/ file (feature → presentation/ui/motion/, generic → DS motion/), reduced-motion gated, no …
- Distinctive: line 200
Add UI Design section to spec referencing the blueprint and design screenshots
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Modify Feature
Apply changes to existing features using spec-first workflow.
Architecture Reference: @../_shared/patterns.md
Hook Marker (Required)
Before editing any feature files, activate the skill marker so the PreToolUse hook allows edits:
touch /tmp/.claude-kmpilot-skill-activeAfter completion (or on any early exit), remove it:
rm -f /tmp/.claude-kmpilot-skill-activeWorkflow
Parse → Spec Check → Design Artifact Detection → Understand → Plan → Draft Spec → [USER APPROVES] → Activate marker → Implement → Validate → Update Spec → Remove marker → Done
Step 1: Parse Feature Name
Extract from request: "add sorting to productlist" → productlist
Validate: ls feature/{featurename}/src/commonMain/kotlin/
Step 2: Spec Check
Load .claude/docs/{featurename}/spec.md
If missing, stop and instruct the user:
No spec found for '{featurename}'. Please run /audit-spec {featurename} first
to generate one, then re-invoke /modify-feature.Do NOT auto-invoke /audit-spec — skills do not call each other; the user controls the pipeline.
Step 3: Design Artifact Detection
Check for a Stitch design blueprint:
- Check blueprint exists:
.claude/docs/{featurename}/designs/{featurename}_blueprint.md - Check stitch-project.json:
.claude/docs/_project/stitch-project.json— readfeatures[featurename].blueprintConsumed - Determine mode:
| Blueprint exists? | blueprintConsumed | Mode |
| Yes | false | Design-aware mode — blueprint drives UI implementation |
| Yes | true | Normal mode — blueprint already consumed |
| No | N/A | Normal mode — no design artifact |
If entering design-aware mode, log:
Design artifact detected: .claude/docs/{featurename}/designs/{featurename}_blueprint.md
Entering design-aware mode. Blueprint will drive UI implementation.Step 4: Understand Current Implementation
Read spec sections: Requirements, Architecture, State Management, Navigation
Step 5: Plan Changes
Platform Profile check (Rule 14): read the spec's Platform Profile & Capabilities field. If this change introduces a device capability or native view (map, camera, GPS, BLE, biometrics, WebView) that the feature didn't have, set/confirm the tag (platform-capability / native-view / mixed) — ask once with AskUserQuestion if ambiguous — and load platform.md. A change that stays network skips this.
Determine affected layers and load architecture as needed:
- Data changes: @../create-feature/architecture/data.md
- UI changes: @../create-feature/architecture/ui.md
- Platform capability / native-view changes (Rule 14): @../create-feature/architecture/platform.md
- Integration changes: @../create-feature/architecture/integration.md
- Bottom-bar tab changes ("add/remove bottom-bar tab", "make this a tab", "show in bottom nav"): @../create-feature/architecture/integration.md → "5. Bottom-Bar Tab (Optional)"
Design-aware branch: If in design-aware mode, read the blueprint's Pre-Implementation Contract section and the ## Motion table (if present). Plan XTheme color updates (missing M3 roles) and Typography Updates Required (font swap + type-scale role overrides) first — both are app-global :core:designsystem edits. The DS motion/ primitives already ship (verify present, reuse — see 1c); plan only feature-specific motion + any genuinely-missing DS primitive. Include the blueprint component tree, the Typography Scale M3 Role mapping, and the ## Motion rows in the UI plan.
Step 6: Draft Spec Changes
Propose updates using diff format:
## Proposed Spec Changes: {featurename}
**Current Version:** X.Y.Z → **Proposed:** X.Y+1.Z
### Section N: {Name}
```diff
existing content
+ added content
- removed contentRationale
{Why these changes are needed}
### Step 7: Review Gate (REQUIRED)
Present changes to user with:
- [ ] **Approve** - Proceed with implementation
- [ ] **Modify** - Request changes
- [ ] **Reject** - Do not proceed
**Never skip this step.**
### Step 8: Implement Changes
Follow patterns from @../_shared/patterns.md
For UI changes: Load @../using-design-system/references/component-mappings.md
**Strings (Rule 12)**: any new user-facing text → a key in the feature's `composeResources/values/strings.xml`, referenced via `stringResource(Res.string.*)` (or `UiText` for ViewModel-origin messages). Never add a hardcoded display literal. If the feature has no `strings.xml` yet, create it. See `@../_shared/patterns.md` → "Strings & Localization (Rule 12)".
**Platform capability / native view (Rule 14)**: when the change adds a device capability or native view, follow `@../create-feature/architecture/platform.md`:
- Capability → `commonMain` DataSource interface returning `Either<DTO>` + per-platform actuals (android/ios/**desktop** fallback) + `expect/actual val platformModule` pulled into `{featurename}Module` via `includes(platformModule)`.
- Native view → `expect @Composable PlatformX` + `AndroidView`/`UIKitView`/desktop actuals under `components/` (Shape C); `{Feature}Content` stays pure Compose.
- Update `build.gradle.kts` per-platform deps (build-gradle-template → "Platform-specific dependencies").
- **iOS actual needs Swift** → write the `iosMain` interface/stub and **stop**: emit *"Run `/bridge-swift` for `{Feature}Bridge`"* in the completion report. Do not write Swift; skills never call each other.
- Bump the spec's **Platform Profile** field to the new tag.
**Bottom-bar tab (optional)**: if the change is "add/remove bottom-bar tab", follow `@../create-feature/architecture/integration.md` → "5. Bottom-Bar Tab (Optional)". This edits only the **app module** (`App.kt`, `navigation/TopLevelDestination.kt`, `composeApp/composeResources/`) — NOT the feature module itself; the feature stays independent. **Add**: append one `TopLevelDestination` enum entry (or scaffold the shell if this is the first tab); the tab label lives in `composeApp/src/commonMain/composeResources/values/strings.xml` (key `tab_{featurename}`), the icon as a vector XML in `composeApp/src/commonMain/composeResources/drawable/` — both referenced via `{PROJECT_NAMESPACE}.composeapp.generated.resources.Res`. **Remove**: delete the enum entry (the route remains a valid pushed destination). No registry exists — orphaned entries/labels/icons must be removed by hand.
**UI file layout (strict allowlist)**: when adding or moving composables, respect the rules in `@../_shared/patterns.md` ("UI File Organization"):
- `{Feature}Screen.kt` accepts only the allowlist names (`Screen`, `ScreenRoot`, and optionally `EmptyContent`); Loading/Failed route to the shared `AppLoadingState`/`AppErrorState` (`{PKG_PREFIX}.designsystem.app`) — never private shells
- Every other composable, including `{Feature}Content`, lives one-per-file under `presentation/ui/components/`
- Non-composable helpers live in `presentation/ui/{Feature}Utils.kt`, never under `components/`
**Previews (mandatory for new components)**: when this modification **adds a new component**, you must also:
1. **Check feature build.gradle.kts** for preview deps:
```kotlin
sourceSets.commonMain.dependencies { implementation(libs.compose.ui.tooling.preview) }
dependencies { androidRuntimeClasspath(libs.compose.ui.tooling) }If either is missing, add it as part of this modification.
Generate a
@Previewcomposable in the same file as the new component, markedprivate, wrapped inXTheme, with realistic sample data. Use the canonical importandroidx.compose.ui.tooling.preview.Preview(CMP 1.11.0+ — common). Never use the deprecatedorg.jetbrains.compose.ui.tooling.preview.Preview.See
@../create-feature/architecture/ui.md→ "Previews" for the full pattern, including@PreviewParameterfor multi-variant previews.
Shared-state screen gate (ALWAYS — runs in normal mode AND design-aware mode, before any code change): Re-read .claude/docs/_project/stitch-project.json. For each state where features[{featurename}].states.{state} == true, check sharedStateScreens.{state}.codeImplemented. If false or absent — execute 1d inline NOW before touching any feature file:
- Resolve
app/dir fromstitch-project.json.designSystem.xthemePath(replace filename, appendapp/). - Read
.claude/docs/_shared/designs/extracted/tokens_{state}.md. - Rewrite
AppLoadingState.kt(loading) orAppErrorState.kt(failed) to match the token inventory. Use only generic DS primitives; never import fromdesignsystem.app; preserve existing function signature,modifierparam, and KDoc. - Set
sharedStateScreens.{state}.codeImplemented = true, updateupdatedAt, write the file. - Build:
./gradlew :core:designsystem:assembleAndroidMain. Re-read and assertcodeImplemented == true— if still not true, repeat from step 3. Never ask the user. Never skip. Never delegate.
Design-aware branch: If in design-aware mode, implement in this order:
XTheme update — Add all missing M3 roles from the blueprint's Pre-Implementation Contract to both
XLightColorsandXDarkColorsinXTheme.kt. Verify build:./gradlew :core:designsystem:assembleAndroidMain1b. Typography update — Read the blueprint's Typography Updates Required +fonts.json. Typography is app-global (lands in:core:designsystem). Font swap (only if a Font swap row exists): runpython3 .claude/skills/_shared/download_font.py --project-root {repo_root} --html .claude/docs/{featurename}/designs/extracted/stitch_success.html --manifest .claude/docs/{featurename}/designs/extracted/fonts.json→ downloads the.ttfset and prints theFont(Res.font.*)lines; replaceXFontFamily()'s body inXTheme.ktwith them (addimport androidx.compose.ui.text.font.FontVariationfor a variable route; follow the printed manual fallback on download failure). Verify build:./gradlew :core:designsystem:assembleAndroidMain. Type-scale role overrides are applied per-node in the feature (sub-step 3), not the theme. Skip 1b entirely when neither sub-table is present. 1c. Motion files (only if the blueprint has a## Motiontable; skip for a static design). Motion needs no asset download — pure Compose in dedicatedmotion/files (see@../_shared/motion.md). The generic DS primitives already ship incore/designsystem/.../motion/(XMotion.kt+expect/actual rememberReducedMotion(),Modifier.shimmer(),PulseDot,AmbientMeshBackground,BokehCanvas,Modifier.pulseGlow(),RevealOnAppear) — verify present, do not recreate. Only if a "DSmotion/" row needs a primitive the shipped set lacks (rare), add it (canonical names from motion.md; a new platform-dependent one needs.android/.ios/.desktopactuals) and build./gradlew :core:designsystem:assembleAndroidMain :core:designsystem:desktopMainClasses. Feature-specific rows land infeature/{featurename}/.../presentation/ui/motion/{Feature}Motion.ktin sub-step 3, reusing the shipped DS primitives with the row's magnitude passed as a parameter. Durations/easings viaXMotiontokens (never ad-hoctween(<literal>)); magnitudes copied verbatim from the## Motiontable (never invented); gate every kept row withrememberReducedMotion(); never inline inScreen.kt/components; never implement interaction/hover motion. 1d. Shared state screen code implementation (MANDATORY — never skip in design-aware mode) — rewritesAppLoadingState.kt/AppErrorState.ktincore/designsystem/.../app/to match the approved Stitch design. The shared state screens carry their own design (one per project) and are not part of the feature blueprint — so if this step is dropped they silently keep the neutralinstall.shdefault and the Stitch redesign never reaches code.For each state in
[loading, failed]wherestitch-project.json.features[{featurename}].states.{state} == trueANDsharedStateScreens.{state}.codeImplementedis nottrue(i.e. it isfalseor the key is absent — legacystitch-project.jsonfiles predate the field; treat an absent key asfalseand implement):- Resolve the
app/dir fromstitch-project.json.designSystem.xthemePath: replace the filename with nothing, appendapp/. Example:core/designsystem/src/commonMain/kotlin/com/example/designsystem/XTheme.kt→core/designsystem/src/commonMain/kotlin/com/example/designsystem/app/. - Read
.claude/docs/_shared/designs/extracted/tokens_{state}.md. - Rewrite
AppLoadingState.kt(loading) orAppErrorState.kt(failed) to match the token inventory. Use only generic design-system primitives (XCircularProgressIndicator,Placeholder,XButton,XIcon,XText, etc.); never import fromdesignsystem.appitself. Preserve the existing function signature,modifierparam, and KDoc. - Set
stitch-project.json.sharedStateScreens.{state}.codeImplemented = true(add the key if it was absent). Update top-levelupdatedAt. Write the file.
Verify (gate — do NOT consider the modification complete until it passes): re-read
stitch-project.jsonand, for every selected state, assertsharedStateScreens.{state}.codeImplemented == true. If any selected state is still nottrue, the rewrite did not happen — STOP and complete it. Then build:./gradlew :core:designsystem:assembleAndroidMain.- Resolve the
X-Component Constraint Check — Collect the unique set of design system source files needed by the blueprint's Component Tree (one file may define many composables — e.g.
XButton.ktdefinesXButton,XOutlinedButton,XIconButton,XTextIconButton,XOutlinedIconButton). Read each file in full and catalog every composable defined in it, not just the one the blueprint named. For each composable, extract:defaultMinSizeconstraints (e.g.XButtonenforcesminWidth=100.dp, minHeight=44.dp)- Default parameter values that differ from what the blueprint intends (e.g.
XIconButtondefaults to a visiblesurfacebackground) - Hardcoded internal padding that overrides
contentPadding(e.g.XTextFieldhardcodestop=10.dp, bottom=10.dp) - Any internal
Modifierapplied via.then(...)that the caller cannot override
Reading the whole file matters: the implementation may legitimately reach for a sibling composable in the same file (e.g. use
XOutlinedButtoninstead ofXButtonfor a pill), and you need its constraints too.For each conflict found, decide the resolution before writing any code:
- Override via modifier:
Modifier.defaultMinSize(Dp.Unspecified)to remove a min-size floor - Override via parameter: pass explicit
colors,shape, orcontentPaddingto win over the default - Accept as architectural limitation: note it — do not fight it with hacks
- Component implementation — Implement UI from the blueprint's Component Tree. Use the blueprint as the primary source, design screenshots as visual cross-reference only. Apply constraint resolutions from sub-step 2. Every text node uses
style = MaterialTheme.typography.{role}(or anXTextDefaultspreset) — never rawfontSize/fontWeight, except a Type-scale role override row (…typography.{role}.copy(...)). Never setfontFamily(global, wired in 1b). Motion (if the blueprint has a## Motiontable): write feature-specific rows intopresentation/ui/motion/{Feature}Motion.kt, call the DSmotion/primitives (from 1c) for generic rows, gate each withrememberReducedMotion()— never inline, never interaction/hover motion.- Images follow each
images.jsonentry'sdelivery:bundled→Image(painter = painterResource({res_reference}))(materialize the raster first if absent: runpython3 .claude/skills/_shared/download_assets.py --type images --feature {featurename} --project-root {repo_root} --html …without--manifest-only— it downloadsbundledonly and skipsremote);remote→AsyncImage(url = {data_binding}, loadingResId = DesignSystemResources.drawable.ds_image_placeholder, …)(design-systemAsyncImage,url=) bound to a data-layer field, never the Stitch CDN URL — add/wire that field on the DTO/*UiModeland keep its Post-Implementation Checklist item. When materializing icons/images, pass one--html .../stitch_{role}.htmlpersecondaryScreens[]entry alongside the selected-state HTML (secondary screens may add their own assets). 3b. Secondary screens (only whenfeatures[{featurename}].secondaryScreens[]is non-empty) — implement the blueprint'sComponent Tree → Secondary Screenssubsections perkind(see_shared/patterns.md→ "Secondary Screens within a Feature"):surface→ render the role's host X-component (XModalBottomSheet/XDialog/XAlertDialog/XModalDrawerSheet/inlineXSurface) from{Feature}ScreenRoot, gated by a{Feature}UiModelvisibility field, opened/closed via callbacks (Rule 10) — no Route;screen→ a full child screen with its own{Feature}{Role}Screen.kt(own allowlist) +components/+{Feature}{Role}Route+ acomposable<{Feature}{Role}Route>inside the sameNavGraphBuilder.{featurename}()extension, navigated from the primary via a hoisted callback. A child route of the feature — not a new Integration Point.
- Images follow each
- Post-Implementation Checklist — Verify every item in the blueprint's Post-Implementation Checklist:
- All XTheme missing roles added to BOTH schemes
- Font swap (if any) applied:
XFontFamily()rewired,:core:designsystembuilds - Every text node uses a
MaterialTheme.typography.{role}— no rawfontSize/fontWeightexcept recorded overrides - Every component in blueprint exists in implementation
- Every Modifier in blueprint is present in code
- All colors use
MaterialTheme.colorScheme.{role}— no rawColor()hex - Component override sizes/colors applied
- Every
images.jsonbundledimage rendered viapainterResource; everyremoteimage rendered viaAsyncImage(url = data field)with itsdata_bindingwired on the DTO/*UiModel(no Stitch CDN URL in code) - Every
## Motionrow implemented in amotion/file (feature →presentation/ui/motion/, generic → DSmotion/), reduced-motion gated, no inline/interaction/hover motion (n/a if no## Motiontable)
Step 9: Validate Build
./gradlew :feature:{featurename}:assembleAndroidMain
./gradlew :feature:{featurename}:ktlintFormatStep 10: Update Specification
Apply APPROVED changes (don't regenerate). Add changelog:
## Last Updated
- {YYYY-MM-DD} - {Brief description}Version bump: Patch (X.Y.Z+1) for fixes, Minor (X.Y+1.0) for features
Design-aware branch: Also:
- Add UI Design section to spec referencing the blueprint and design screenshots
- Set
"blueprintConsumed": truein.claude/docs/_project/stitch-project.jsonunderfeatures[{featurename}]
Error Handling
Build errors: Load @../create-feature/troubleshooting/index.md
Design system: Activate /using-design-system
Completion Checklist
- Spec changes drafted and USER APPROVED
- Build passes
- Code formatted (ktlint)
- Spec updated with approved changes
- Changelog entry added
- Version bumped
- (Design-aware) blueprintConsumed set to true in stitch-project.json
What's next
Emit this blockquote as the very last line of output:
Next step — run
/clearto free the context window (the spec + design blueprint are durable artifacts — the next skill re-reads them fresh, so clearing loses nothing), then/review-feature {featurename}to validate the changes — or/verify-ui {featurename}if you applied a design.
Other versions1 project uses a version of this.
Word for word · 1
- ThisIsSadeghi/Loupe★ 1100% same
Edited · 0
None found.
Wrote their own version · 0
None found.
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository6 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- bridge-swiftSkill
- create-featureSkill
- design-uiSkill
- using-design-systemSkill
- verify-uiSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

