Skip to content

Instantly share code, notes, and snippets.

@kumeS
Created May 13, 2025 03:56
Show Gist options
  • Select an option

  • Save kumeS/04193157125aa2fa02a60a8f4b4ed0b6 to your computer and use it in GitHub Desktop.

Select an option

Save kumeS/04193157125aa2fa02a60a8f4b4ed0b6 to your computer and use it in GitHub Desktop.
A bash script automating iOS app setup via CLI: creates project folders, SwiftUI entrypoint & API key file, generates .xcodeproj with XcodeGen, builds, launches on simulator, and scaffolds config/docs.
#!/usr/bin/env bash
set -euo pipefail
#===================================================
# init_ios_project.sh
# - Takes a project name as argument and automates:
# 1. Directory structure & Sources/Config, Resources, Tests creation
# 2. Generating APIKeys.swift & SwiftUI entry point
# 3. project.yml + XcodeGen to produce .xcodeproj
# 4. Build → install → launch on simulator
# 5. Generating .env.example, .gitignore, .swiftlint.yml, .swiftformat,
# Tests/*Tests.swift, .cursor/rules, README.md, Makefile, AGENT_GUIDE.md
#===================================================
if [ $# -lt 1 ]; then
echo "Usage: $0 <ProjectName>"
exit 1
fi
PROJECT="$1"
BUNDLE_ID="com.example.${PROJECT}"
# 1) Detect available iPhone simulator
SIM_NAME=$(
xcrun simctl list devices available \
| grep -E "iPhone [0-9]+" \
| head -n1 \
| sed -E 's/.*(iPhone [0-9A-Za-z \-]+) \(.*/\1/'
)
if [ -z "$SIM_NAME" ]; then
echo "⚠️ No iPhone simulator found, falling back to generic"
DEST="generic/platform=iOS Simulator"
else
echo "▶ Detected simulator: ${SIM_NAME}"
DEST="platform=iOS Simulator,name=${SIM_NAME}"
fi
echo "▶ Destination: ${DEST}"
# 2) Create directories and initial files
mkdir -p "${PROJECT}"/{Sources,Resources,Tests,Sources/Config}
cd "${PROJECT}"
# 2.1) APIKeys.swift
cat <<'EOF' > Sources/Config/APIKeys.swift
/**
* API Keys configuration file
*
* Usage:
* 1. Copy this file to `APIKeys.swift`
* 2. Replace placeholder values with actual API keys
* 3. Confirm it is excluded by .gitignore
*/
enum APIKeys {
/// OpenAI API Key
/// Requires appropriate access to GPT-4 Vision
/// Get yours at https://platform.openai.com/
static let openAI = "YOUR_OPENAI_API_KEY_HERE"
}
EOF
# 2.2) SwiftUI entry point
cat <<EOF > Sources/${PROJECT}App.swift
import SwiftUI
@main
struct ${PROJECT}App: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
var body: some View {
Text("Hello, ${PROJECT}!")
.padding()
}
}
EOF
# 3) Generate project.yml for XcodeGen
cat <<EOF > project.yml
name: ${PROJECT}
options:
bundleIdPrefix: com.example
settings:
SWIFT_VERSION: 5.9
configs:
Debug: debug
Release: release
targets:
${PROJECT}:
type: application
platform: iOS
deploymentTarget: "17.0"
sources: [Sources]
settings:
PRODUCT_BUNDLE_IDENTIFIER: ${BUNDLE_ID}
GENERATE_INFOPLIST_FILE: YES
EOF
# 4) Run XcodeGen to create the Xcode project
echo "▶ Running xcodegen..."
xcodegen generate
# 5) Build, install, and launch on simulator
DERIVED_DATA="build"
echo "▶ Building project..."
xcodebuild \
-scheme "${PROJECT}" \
-destination "${DEST}" \
-derivedDataPath "${DERIVED_DATA}" \
build
if [[ "${DEST}" != generic* ]]; then
echo "▶ Booting simulator..."
xcrun simctl boot "${SIM_NAME}" || true
APP_PATH="${DERIVED_DATA}/Build/Products/Debug-iphonesimulator/${PROJECT}.app"
echo "▶ Installing app..."
xcrun simctl install booted "${APP_PATH}"
echo "▶ Launching app..."
xcrun simctl launch booted "${BUNDLE_ID}"
else
echo "▶ Generic simulator: skipping install & launch"
fi
# 6) Create supporting configuration and guide files
# .env.example
cat <<EOF > .env.example
# Example environment variables
OPENAI_API_KEY=your_openai_api_key_here
EOF
# .gitignore
cat <<EOF > .gitignore
# Exclude API keys file
Sources/Config/APIKeys.swift
# Environment files
.env
# Build artifacts
build/
DerivedData/
# SwiftLint cache
.swiftlint.yml
EOF
# SwiftLint configuration
cat <<EOF > .swiftlint.yml
disabled_rules:
- trailing_whitespace
- line_length
EOF
# SwiftFormat configuration
cat <<EOF > .swiftformat
--indent 4
--line-length 100
EOF
# Basic unit test template
cat <<EOF > Tests/${PROJECT}Tests.swift
import XCTest
@testable import ${PROJECT}
final class ${PROJECT}Tests: XCTestCase {
func testExample() throws {
XCTAssertTrue(true)
}
}
EOF
# .cursor/rules
mkdir -p .cursor
cat << 'EOF' > .cursor/rules
style:
- Use Swift 5.9, SwiftUI 3, async/await only
folders:
- Sources: src code
- Sources/Config: config code
- Resources: assets & plist
- Tests: unit tests
restrictions:
- Do NOT import UIKit unless explicitly asked
- Keep imports alphabetically sorted
- Log with os_log only
testing:
- Always add failing unit test before bug-fix
file_safety:
protect:
- "*.xcodeproj"
- "*.xcworkspace"
- "init_ios_project.sh"
- "Makefile"
- ".cursor/rules"
- "README.md"
- "AGENT_GUIDE.md"
- "Sources/Config/APIKeys.swift"
delete:
allow_patterns:
- "DerivedData/**"
- "build/**"
forbid_patterns:
- "Sources/**"
- "Resources/**"
- "Tests/**"
tests:
enforce_location: "Tests/"
naming_pattern: "*Tests.swift"
max_per_feature: 3
EOF
# README.md
cat << EOF > README.md
# ${PROJECT}
## Overview
**Description:** (Brief app description)
**Target:** iOS 17 / Swift 5.9
**Bundle ID:** ${BUNDLE_ID}
## Features
1. Feature A
2. Feature B
3. Feature C
## Usage
\`\`\`bash
make run
\`\`\`
EOF
# Makefile
cat << 'EOF' > Makefile
SCHEME = ${PROJECT}
DEST = ${DEST}
build:
xcodebuild -scheme $(SCHEME) -destination $(DEST) -derivedDataPath build build
run: build
@[ "\$(echo \$(DEST) | grep -q '^platform'; echo \$?)" -eq 0 ] && \
xcrun simctl boot "${SIM_NAME}" && \
xcrun simctl install booted build/Build/Products/Debug-iphonesimulator/\$(SCHEME).app && \
xcrun simctl launch booted com.example.\$(SCHEME) || \
echo "⚠️ generic simulator; skipping install & launch"
test:
xcodebuild test -scheme $(SCHEME) -destination $(DEST) -derivedDataPath build
format:
swift format .
clean:
rm -rf build
xcodebuild clean -scheme $(SCHEME)
EOF
# AGENT_GUIDE.md
cat << 'EOF' > AGENT_GUIDE.md
# Agent Interaction Guide
## Getting Started
1. Open the project folder in Cursor Editor: \`cd ${PROJECT}\`
2. From the gear icon, select **Index Workspace**
## Sample Agent Prompts
- 🛠 Create a new SwiftUI view "QuizListView" under Sources/QuizListView.swift with Preview.
- 🐛 Fix import errors by adding \`import Vision\` and \`import OpenAI\` to Sources/OCRService.swift, then rebuild.
- 🎨 Change ContentView text from "Hello, ${PROJECT}!" to "Welcome!", preview, and run on simulator.
## One-Liner Build & Run
\`\`\`bash
make run
\`\`\`
## Troubleshooting Templates
- 🚑 Paste simctl logs and ask: “What’s causing this simulator error and how to fix it?”
- 🔍 Paste full build logs and ask: “Identify the build error and provide a patch.”
EOF
echo "✅ Initialization complete! cd ${PROJECT} → open in Cursor Editor and index the workspace."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment