fosmvvm-swiftui-app-setup
// Set up the @main App struct for FOSMVVM SwiftUI apps. Configures MVVMEnvironment, deployment URLs, and test infrastructure.
FOSMVVM SwiftUI App Setup
Generate the main App struct for a SwiftUI application using FOSMVVM architecture.
Conceptual Foundation
For full architecture context, see FOSMVVMArchitecture.md | OpenClaw reference
The App struct is the entry point of a SwiftUI application. In FOSMVVM, it has three core responsibilities:
┌─────────────────────────────────────────────────────────────┐
│ @main App Struct │
├─────────────────────────────────────────────────────────────┤
│ 1. MVVMEnvironment Setup │
│ - Bundles (app + localization resources) │
│ - Deployment URLs (production, staging, debug) │
│ │
│ 2. Environment Injection │
│ - .environment(mvvmEnv) on WindowGroup │
│ - Custom environment values │
│ │
│ 3. Test Infrastructure (DEBUG only) │
│ - .testHost { } modifier for UI testing │
│ - registerTestingViews() for individual view testing │
└─────────────────────────────────────────────────────────────┘
Core Components
1. MVVMEnvironment
The MVVMEnvironment provides FOSMVVM infrastructure to all views:
private var mvvmEnv: MVVMEnvironment {
MVVMEnvironment(
appBundle: Bundle.main,
resourceBundles: [
MyAppViewModelsResourceAccess.localizationBundle,
SharedResourceAccess.localizationBundle
],
deploymentURLs: [
.production: .init(serverBaseURL: URL(string: "https://api.example.com")!),
.debug: .init(serverBaseURL: URL(string: "http://localhost:8080")!)
]
)
}
Key configuration:
appBundle- UsuallyBundle.main(the app bundle)resourceBundles- Array of localization bundles from your modulesdeploymentURLs- URLs for each deployment environment
Resource Bundle Accessors:
Each module that contains localization resources should provide a bundle accessor:
// In your ViewModels module (e.g., MyAppViewModels/ResourceAccess.swift)
public enum MyAppViewModelsResourceAccess {
public static var localizationBundle: Bundle { Bundle.module }
}
This pattern:
- Uses
Bundle.modulewhich SPM automatically provides for each module - Provides a clean public API for accessing the module's resources
- Keeps bundle access centralized in one place per module
2. Environment Injection
The MVVMEnvironment is injected at the WindowGroup level:
var body: some Scene {
WindowGroup {
MyView()
}
.environment(mvvmEnv) // ← Makes FOSMVVM infrastructure available
}
This makes the environment available to all views in the hierarchy.
3. Test Infrastructure
The test infrastructure enables UI testing with specific configurations:
.testHost { } modifier:
var body: some Scene {
WindowGroup {
ZStack {
LandingPageView()
}
#if DEBUG
.testHost { testConfiguration, testView in
// Handle specific test configurations...
default:
testView
.onAppear {
underTest = ProcessInfo.processInfo.arguments.count > 1
}
}
#endif
}
}
Key points:
- Apply to the top-level view in WindowGroup (the outermost view in your hierarchy)
- This ensures the modifier wraps the entire view hierarchy to intercept test configurations
- Always include the
default:case - The default case detects test mode via process arguments
- Sets
@State private var underTest = falseflag - Optional: Add specific test configurations for advanced scenarios
registerTestingViews() function:
#if DEBUG
private extension MyApp {
@MainActor func registerTestingViews() {
mvvmEnv.registerTestView(LandingPageView.self)
mvvmEnv.registerTestView(SettingsView.self)
// ... register all ViewModelViews for individual testing
}
}
#endif
Key points:
- Extension on the App struct (not MVVMEnvironment)
- Called from
init() - Registers every ViewModelView for isolated testing
- DEBUG only
When to Use This Skill
- Starting a new FOSMVVM SwiftUI application
- Migrating an existing SwiftUI app to FOSMVVM
- Setting up the App struct with proper FOSMVVM infrastructure
- Configuring test infrastructure for UI testing
What This Skill Generates
| Component | Location | Purpose |
|---|---|---|
| Main App struct | Sources/App/{AppName}.swift | Entry point with MVVMEnvironment setup |
| MVVMEnvironment configuration | Computed property in App struct | Bundles and deployment URLs |
| Test infrastructure | DEBUG blocks in App struct | UI testing support |
Project Structure Configuration
| Placeholder | Description | Example |
|---|---|---|
{AppName} | Your app name | MyApp, AccelApp |
{AppTarget} | Main app target | App |
{ResourceBundles} | Module names with localization | MyAppViewModels, SharedResources |
How to Use This Skill
Invocation: /fosmvvm-swiftui-app-setup
Prerequisites:
- App name understood from conversation context
- Deployment URLs discussed or documented
- Resource bundles identified (modules with localization)
- Test support requirements clarified
Workflow integration: This skill is used when setting up a new FOSMVVM SwiftUI application or adding FOSMVVM infrastructure to an existing app. The skill references conversation context automatically—no file paths or Q&A needed.
Pattern Implementation
This skill references conversation context to determine App struct configuration:
Configuration Detection
From conversation context, the skill identifies:
- App name (from project discussion or existing code)
- Deployment environments (production, staging, debug URLs)
- Resource bundles (modules containing localization YAML files)
- Test infrastructure (whether UI testing support needed)
MVVMEnvironment Setup
Based on project structure:
- App bundle (typically Bundle.main)
- Resource bundle accessors (from identified modules)
- Deployment URLs (for each environment)
- Current version (from shared module)
Test Infrastructure Planning
If test support needed:
- Test detection (process arguments check)
- Test host modifier (wrapping top-level view)
- View registration (all ViewModelViews for testing)
File Generation
- Main App struct with @main attribute
- MVVMEnvironment computed property
- WindowGroup with environment injection
- Test infrastructure (if requested, DEBUG-only)
- registerTestingViews() extension (if test support)
Context Sources
Skill references information from:
- Prior conversation: App requirements, deployment environments discussed
- Project structure: From codebase analysis of module organization
- Existing patterns: From other FOSMVVM apps if context available
Key Patterns
MVVMEnvironment as Computed Property
The MVVMEnvironment is a computed property, not a stored property:
private var mvvmEnv: MVVMEnvironment {
MVVMEnvironment(
appBundle: Bundle.main,
resourceBundles: [...],
deploymentURLs: [...]
)
}
Why computed?
- Keeps initialization logic separate
- Can be customized in DEBUG vs RELEASE
- Clear dependency on bundles and URLs
Test Detection Pattern
The default test detection uses process arguments:
@State private var underTest = false
// In .testHost default case:
testView
.onAppear {
// Right now there's no other way to detect if the app is under test.
// This is only debug code, so we can proceed for now.
underTest = ProcessInfo.processInfo.arguments.count > 1
}
Why this approach?
- Simple and reliable for DEBUG builds
- No additional dependencies
- Process arguments are set by test runner
Register All ViewModelViews
Every ViewModelView should be registered for testing:
@MainActor func registerTestingViews() {
// Landing Page
mvvmEnv.registerTestView(LandingPageView.self)
// Settings
mvvmEnv.registerTestView(SettingsView.self)
mvvmEnv.registerTestView(ProfileView.self)
// Dashboard
mvvmEnv.registerTestView(DashboardView.self)
mvvmEnv.registerTestView(CardView.self)
}
Organization tips:
- Group by feature/screen with comments
- Alphabetical order within groups
- One view per line for easy scanning
Common Customizations
Multiple Environment Values
You can inject multiple environment values:
var body: some Scene {
WindowGroup {
MyView()
}
.environment(mvvmEnv)
.environment(appState)
.environment(\.colorScheme, .dark)
.environment(\.customValue, myCustomValue)
}
Conditional Test Registration
You can conditionally register views based on build configuration:
#if DEBUG
@MainActor func registerTestingViews() {
mvvmEnv.registerTestView(LandingPageView.self)
#if INCLUDE_ADMIN_FEATURES
mvvmEnv.registerTestView(AdminPanelView.self)
#endif
}
#endif
Advanced Test Configurations
You can add specific test configurations in .testHost:
.testHost { testConfiguration, testView in
switch try? testConfiguration.fromJSON() as MyTestConfiguration {
case .specificScenario(let data):
testView.environment(MyState.stub(data: data))
.onAppear { underTest = true }
default:
testView
.onAppear {
underTest = ProcessInfo.processInfo.arguments.count > 1
}
}
}
File Templates
See reference.md for complete file templates.
Naming Conventions
| Concept | Convention | Example |
|---|---|---|
| App struct | {Name}App | MyApp, AccelApp |
| Main file | {Name}App.swift | MyApp.swift |
| MVVMEnvironment property | mvvmEnv | Always mvvmEnv |
| Test flag | underTest | Always underTest |
Deployment Configuration
FOSMVVM supports deployment detection via Info.plist:
CI Pipeline Sets:
FOS_DEPLOYMENT build setting (e.g., "staging" or "production")
↓
Info.plist Contains:
FOS-DEPLOYMENT = $(FOS_DEPLOYMENT)
↓
Runtime Detection:
FOSMVVM.Deployment.current reads from Bundle.main.infoDictionary
Local development override:
- Edit Scheme → Run → Arguments → Environment Variables
- Add:
FOS-DEPLOYMENT = staging
See Also
- Architecture Patterns - Mental models and patterns
- FOSMVVMArchitecture.md - Full FOSMVVM architecture
- fosmvvm-viewmodel-generator - For creating ViewModels
- reference.md - Complete file templates
Version History
| Version | Date | Changes |
|---|---|---|
| 1.0 | 2026-01-23 | Initial skill for SwiftUI app setup |
| 1.1 | 2026-01-24 | Update to context-aware approach (remove file-parsing/Q&A). Skill references conversation context instead of asking questions or accepting file paths. |