Exploring Cursor: Generating Cursor Rules
After being on-boarded to a new code base, I subscribed back to Cursor for iOS development. The latest version, 0.49, added a useful feature: you can now create "Cursor Rules" just by chatting with the AI.
All you do is type /Generate Cursor Rules
in a chat!
This makes it easy to tell Cursor how you want it to code for your specific project.
What Are Cursor Rules?
Think of Cursor Rules as instructions as additional context for the language models. They tell it things like:
- Which coding style to follow,
- To use specific tools or frameworks (like the latest SwiftUI features),
- How your project is structured.
For iOS apps, you can tell Cursor: "Always use NavigationStack instead of the old NavigationView," "Make sure the code follows Apple's API design guidelines," or "Prioritize using @Observable for state management."
The New /Generate Cursor Rules
Feature
Before version 0.49, setting up these rules involved manually creating and editing files.
Now, you can simply use the /Generate Cursor Rules
command after discussing your project's needs with Cursor. It analyzes the conversation and drafts the rules for you. You can then refine them further through chat, asking Cursor to save the information into existing rule files or create new ones as needed.
How I Use /Generate Cursor Rules
I started on a new SwiftUI project and wanted to lay down rules as the first priority:
I opened Cursor's Composer (Command + I) and directly used the /Generate Cursor Rules
command.
Cursor first listed all the current directories, then the files in different targets. Then, it searched for existing rules by searching for .mdc
files.
As the project did not had any, it then went on creating a new directory for the rules:
mkdir -p .cursor/rules
It first generated project_structure.mdc
which is something along the lines:
**Project Structure Guide**
This project is organized using a modular approach, combining a main application target with several distinct Swift Packages.
* **Main Application Directory (`App/`)**: This directory houses the core application code for iOS/macOS. It includes:
* The application's entry point (e.g., `App` struct using SwiftUI, `AppDelegate`).
* Configuration files and essential services or managers.
* Subdirectories for components like API interaction, utilities, UI views, custom shaders (if any), environment settings, and resources (like assets).
* **Sample Project Directory (`Examples/` or `SampleApp/`)**: Contains a separate, runnable sample project. This is used to demonstrate specific features or usage patterns of the project's packages/modules. It includes:
* Example SwiftUI views demonstrating functionality.
* Supporting code files required for the sample to run (e.g., sample data managers).
* **Feature-Specific Swift Packages (`Packages/` or at root level)**: The project is broken down into multiple Swift Packages, each providing distinct functionality. These might include packages responsible for:
* Data searching capabilities.
* Content generation or suggestions.
* Networking utilities and API clients.
* Integration with language models or AI services.
* Web searching or scraping tools.
* Performance profiling or analytics features.
* **Xcode Project Configuration**: Standard files manage the build settings, capabilities, and metadata for the main application target:
* An `.xcodeproj` file defining the project structure and build targets.
* An `.entitlements` file specifying application capabilities (like network access or iCloud).
* An `Info.plist` file containing application metadata.
Each Swift package typically resides in its own directory at the project's root level (or within a dedicated `Packages/` folder). They provide modular, reusable code that is imported into the main application or other packages as dependencies.
Then, it mentioned about building and running the project. This was helpful to directly build and run the project on simulator after adding a new feature or fixing an issue:
# Build and Run Guide
## Main App
```bash
xcodebuild -project genie.xcodeproj -scheme Genie -configuration Debug -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 14'
```
## Swift Packages
Each Swift package in the root directory can be built and tested independently:
```bash
cd <PackageDirectory>
swift build
swift test
```
It asked me if I wanted additional rules on testing guidelines, environment setup, coding conventions, and I told it to go through the codebase to write one on latest SwiftUI as well. Here is the one on coding convention. Feel free to pick up something that you prefer:
# Coding Conventions
This rule outlines Swift and project-wide coding conventions to ensure consistency and maintainability.
## General Guidelines
- Follow Apple's Swift API Design Guidelines for clear and expressive naming.
- Prefer immutability: use `let` over `var` whenever possible.
- Use `guard` statements for early exits and error handling.
- Avoid force-unwrapping (`!`); use optional binding (`if let`/`guard let`) or safe `try?`.
- Limit line length to 100 characters.
## Naming
- Types (structs, classes, enums, protocols): UpperCamelCase.
- Variables, properties, functions, and methods: lowerCamelCase.
- Constants and enum cases: lowerCamelCase.
- Acronyms: capitalize only the first letter (e.g., `HttpRequest`, not `HTTPRequest`).
## File Organization
- One top-level type per file; filename matches the type name.
- Group related extensions in `Type+ExtensionName.swift` files.
- Organize imports: system libraries first, then third-party, then local modules.
## Formatting
- Indent with 4 spaces (no tabs).
- Use one blank line between methods and properties; two blank lines between types.
- Place braces on the same line: `func foo() {`.
- Use trailing closures when a closure is the last argument.
- Prefer labeled parameters over shorthand closure arguments (`$0`) for clarity.
## Documentation
- Document public APIs with `///` doc comments.
- Use Swift-Doc or Jazzy to generate documentation from comments.
- Annotate deprecated or unavailable APIs with `@available`.
## Error Handling
- Use `throws` and `do-try-catch` for error propagation.
- Define custom `Error` types with descriptive cases.
## Linting and Formatting Tools
- Integrate SwiftLint: include a `.swiftlint.yml` with the agreed rule set.
- Use `swiftformat` or `swift-format` to enforce consistent style.
And one on SwiftUI:
# SwiftUI Latest Features Guide
This rule outlines best practices for leveraging the latest SwiftUI features (iOS 17+, macOS Sonoma+).
## Data Models and Persistence
- Use `@Model` from SwiftData for persistent data models with minimal boilerplate.
- Leverage the `@Observable` macro for lightweight observable types.
## Async and Concurrency in Views
- Use `.task(id:)` and `.refreshable` modifiers for asynchronous data fetching in views.
- Utilize structured concurrency (`async let`, `await`) within view builders.
## Navigation and Layout
- Use `NavigationSplitView` for adaptive multi-column navigation on iPad and macOS.
- Use `NavigationStack` with `NavigationPath` for type-safe, deep navigation flows.
## Custom Layouts
- Adopt the `Layout` protocol to define custom layout containers.
- Use built-in `Grid`, `Row`, and `Column` types for complex arrangements.
## Styling and Theming
- Use `Material`, `ThinMaterial`, and `ThickMaterial` backgrounds for adaptive theming.
- Define app-wide theme values via custom `@Environment` keys or `@AppStorage`.
## Charts and Graphics
- Use the `Charts` framework (`Chart`, `BarMark`, `LineMark`, etc.) for built-in data visualizations.
- Leverage `Canvas` and `TimelineView` for custom drawing and time-based updates.
## Macros and Previews
- Use the `#Preview` macro for multiple view configurations in Xcode previews.
- Leverage property wrapper macros like `@State`, `@Binding`, `@Environment`, `@Query` for concise code.
## Accessibility and Localization
- Use `.accessibilityLabel`, `.accessibilityValue`, and `.accessibilityAction` modifiers to annotate views.
- Support dynamic type via `.dynamicTypeSize` and control layout with `layoutPriority(_:)`.
- Use `.localeEffect(_:)` for localized formatting and number/date styles.
## Animations and Transitions
- Use explicit animations: `.animation(.default, value: state)`.
- Leverage `.matchedGeometryEffect(id:in:)` for seamless transitions across view hierarchies.
That's it! This new feature in Cursor 0.49 makes it a bit simpler to customize the rules for your iOS projects, letting you generate the mundane rules faster.
Moving Forward
I will iterate on these rules as I get more accustomed to the codebase, and maintain its consistency with the colleagues.
For now, I added the .cursor
to .gitignore
for myself until I discuss with others if they like the "AI" generated rules!
Happy Cursoring!