A shell is the product frame: navigation, layout, runtime/device state, and where surfaces appear. It should place surfaces, not become every feature.
Your app has a sidebar, a main panel, and a details panel. The shell decides those regions exist. Package surfaces decide what product body appears inside them.Shell
Navigation, route, account state, runtime/device state, and layout regions.
→
Descriptor
Which product surface belongs in which shell region.
→
Surface
Reads named data, renders UI states, and sends named action requests.
Shell ownership
| Shell can own | Shell should not own |
|---|---|
| Navigation | Customer archive logic |
| Region layout | Package record parsing |
| Active-device banners | Target payload interpretation |
| Account/key prompts | Product-specific empty states |
| Surface placement | Package-owned file contents |
Placeable surface rule
The shell should be able to place a surface from a descriptor without importing the feature’s private screens, stores, actions, or file layout.What this prevents
| Bad shape | What happens by month six |
|---|---|
| Shell imports every feature component and action helper | Navigation becomes the product’s largest dependency graph |
| Surface placement is hardcoded inside feature logic | Reusing the same feature in another shell becomes painful |
| Account/device state is copied into every surface | Every screen handles activation differently |
Verify
You have the right boundary when you can move a surface frommain to details without editing the target implementation or named data read contract.