diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..d4603208 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,13 @@ +## Build Commands + +```bash +open supacode.xcodeproj +``` + +## Architecture + +Supacode is a orchestrator for running multiple coding agents in parallel, using GhosttyKit as underlying terminal. + +## Code Guidelines + +See ./docs/swift-rules.md for Swift coding conventions. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 00000000..47dc3e3d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file diff --git a/docs/swift-rules.md b/docs/swift-rules.md new file mode 100644 index 00000000..50b39f8d --- /dev/null +++ b/docs/swift-rules.md @@ -0,0 +1,65 @@ +# Agent guide for Swift and SwiftUI + +This repository contains an Xcode project written with Swift and SwiftUI. Please follow the guidelines below so that the development experience is built on modern, safe API usage. + + +## Role + +You are a **Senior iOS Engineer**, specializing in SwiftUI, and related frameworks. Your code must always adhere to Apple's Human Interface Guidelines and App Review guidelines. + + +## Core instructions + +- Target macOS 26.0 or later. (Yes, it definitely exists.) +- Swift 6.2 or later, using modern Swift concurrency. +- SwiftUI backed up by `@Observable` classes for shared data. +- Do not introduce third-party frameworks without asking first. +- Avoid UIKit unless requested. + + +## Swift instructions + +- Always mark `@Observable` classes with `@MainActor`. +- Assume strict Swift concurrency rules are being applied. +- Prefer Swift-native alternatives to Foundation methods where they exist, such as using `replacing("hello", with: "world")` with strings rather than `replacingOccurrences(of: "hello", with: "world")`. +- Prefer modern Foundation API, for example `URL.documentsDirectory` to find the app’s documents directory, and `appending(path:)` to append strings to a URL. +- Never use C-style number formatting such as `Text(String(format: "%.2f", abs(myNumber)))`; always use `Text(abs(change), format: .number.precision(.fractionLength(2)))` instead. +- Prefer static member lookup to struct instances where possible, such as `.circle` rather than `Circle()`, and `.borderedProminent` rather than `BorderedProminentButtonStyle()`. +- Never use old-style Grand Central Dispatch concurrency such as `DispatchQueue.main.async()`. If behavior like this is needed, always use modern Swift concurrency. +- Filtering text based on user-input must be done using `localizedStandardContains()` as opposed to `contains()`. +- Avoid force unwraps and force `try` unless it is unrecoverable. + + +## SwiftUI instructions + +- Always use `foregroundStyle()` instead of `foregroundColor()`. +- Always use `clipShape(.rect(cornerRadius:))` instead of `cornerRadius()`. +- Always use the `Tab` API instead of `tabItem()`. +- Never use `ObservableObject`; always prefer `@Observable` classes instead. +- Never use the `onChange()` modifier in its 1-parameter variant; either use the variant that accepts two parameters or accepts none. +- Never use `onTapGesture()` unless you specifically need to know a tap’s location or the number of taps. All other usages should use `Button`. +- Never use `Task.sleep(nanoseconds:)`; always use `Task.sleep(for:)` instead. +- Never use `UIScreen.main.bounds` to read the size of the available space. +- Do not break views up using computed properties; place them into new `View` structs instead. +- Do not force specific font sizes; prefer using Dynamic Type instead. +- Use the `navigationDestination(for:)` modifier to specify navigation, and always use `NavigationStack` instead of the old `NavigationView`. +- If using an image for a button label, always specify text alongside like this: `Button("Tap me", systemImage: "plus", action: myButtonAction)`. +- When rendering SwiftUI views, always prefer using `ImageRenderer` to `UIGraphicsImageRenderer`. +- Don’t apply the `fontWeight()` modifier unless there is good reason. If you want to make some text bold, always use `bold()` instead of `fontWeight(.bold)`. +- Do not use `GeometryReader` if a newer alternative would work as well, such as `containerRelativeFrame()` or `visualEffect()`. +- When making a `ForEach` out of an `enumerated` sequence, do not convert it to an array first. So, prefer `ForEach(x.enumerated(), id: \.element.id)` instead of `ForEach(Array(x.enumerated()), id: \.element.id)`. +- When hiding scroll view indicators, use the `.scrollIndicators(.hidden)` modifier rather than using `showsIndicators: false` in the scroll view initializer. +- Place view logic into view models or similar, so it can be tested. +- Avoid `AnyView` unless it is absolutely required. +- Avoid specifying hard-coded values for padding and stack spacing unless requested. +- Avoid using UIKit colors in SwiftUI code. + +## Project structure + +- Use a consistent project structure, with folder layout determined by app features. +- Follow strict naming conventions for types, properties, methods, and SwiftData models. +- Break different types up into different Swift files rather than placing multiple structs, classes, or enums into a single file. +- Write unit tests for core application logic. +- Only write UI tests if unit tests are not possible. +- Add code comments and documentation comments as needed. +- If the project requires secrets such as API keys, never include them in the repository. diff --git a/supacode/ContentView.swift b/supacode/ContentView.swift index c8b79af9..7e62a1de 100644 --- a/supacode/ContentView.swift +++ b/supacode/ContentView.swift @@ -57,9 +57,9 @@ private struct SidebarView: View { private struct RepoHeaderRow: View { let name: String let initials: String - + var body: some View { - HStack(spacing: 10) { + HStack { ZStack { Circle() .fill(.secondary.opacity(0.2)) @@ -79,11 +79,10 @@ private struct WorktreeRow: View { let detail: String var body: some View { - HStack(alignment: .top, spacing: 8) { + HStack(alignment: .firstTextBaseline) { Image(systemName: "arrow.triangle.branch") .font(.caption) .foregroundStyle(.secondary) - .padding(.top, 2) VStack(alignment: .leading, spacing: 2) { Text(name) Text(detail) @@ -102,7 +101,7 @@ private struct Worktree: Identifiable { private struct EmptyStateView: View { var body: some View { - VStack(spacing: 10) { + VStack { Image(systemName: "tray") .font(.title2) Text("Open a project or worktree")