Skip to content

Qard/opencode-swift

Repository files navigation

OpenCode

A native macOS and iOS client for OpenCode, providing a SwiftUI-based interface for AI-powered coding assistance with real-time streaming, session management, and project-aware interactions.

Features

  • Cross-Platform: Native support for both macOS (14.0+) and iOS (17.0+)
  • Real-Time Streaming: Server-Sent Events (SSE) for live updates
  • Session Management: Create, manage, and navigate between multiple chat sessions
  • Project-Aware: Directory-based context with automatic file tracking
  • Agent Selection: Switch between different AI agents and models
  • Task Management: Inline TODO task tracking and management
  • Permissions System: Granular control over file operations and command execution
  • Background Support: Notifications and background processing for long-running operations

Requirements

  • macOS: 14.0 (Sonoma) or later
  • iOS: 17.0 or later
  • Xcode: 15.0 or later (for Xcode-based workflows)
  • Swift: 6.2 or later
  • XcodeGen: For generating Xcode projects (install via Homebrew: brew install xcodegen)
  • OpenCode: A running OpenCode server and CLI instance

Installation

Quick Start (CLI)

  1. Clone the repository:

    git clone https://github.com/Qard/opencode-swift.git
    cd opencode-swift
  2. Resolve dependencies:

    swift package resolve
  3. Build the project:

    swift build

Note: The .xcodeproj file is not tracked in git. Use XcodeGen to generate it when needed (see below).

Generating the Xcode Project

This project uses XcodeGen to generate the Xcode project from project.yml. The .xcodeproj file is gitignored to avoid merge conflicts.

  1. Install XcodeGen (if not already installed):

    brew install xcodegen
  2. Generate the Xcode project:

    xcodegen
  3. Open the generated project:

    open OpenCode.xcodeproj

Building the Applications

macOS Application

CLI Build (Development)

Build the macOS app using xcodebuild:

# Generate Xcode project first (if needed)
xcodegen

# Build for macOS
xcodebuild -project OpenCode.xcodeproj \
           -scheme "OpenCode macOS" \
           -configuration Debug \
           -derivedDataPath .build

# The app bundle will be at:
# .build/Build/Products/Debug/OpenCode.app

Run the development build:

open .build/Build/Products/Debug/OpenCode.app

Or install to Applications:

cp -r .build/Build/Products/Debug/OpenCode.app /Applications/

CLI Build (Release)

First, create ExportOptions-macOS.plist with your team ID:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>method</key>
    <string>developer-id</string>
    <key>teamID</key>
    <string>YOUR_TEAM_ID</string>
</dict>
</plist>

For Mac App Store distribution, use <string>app-store</string> instead of developer-id.

Then build and export the release version:

xcodebuild -project OpenCode.xcodeproj \
           -scheme "OpenCode macOS" \
           -configuration Release \
           -derivedDataPath .build \
           archive \
           -archivePath .build/OpenCode-macOS.xcarchive

# Export the archive
xcodebuild -exportArchive \
           -archivePath .build/OpenCode-macOS.xcarchive \
           -exportPath .build/Release \
           -exportOptionsPlist ExportOptions-macOS.plist

Creating a DMG (macOS)

# Install create-dmg if needed
brew install create-dmg

# Create DMG from built app
create-dmg \
  --volname "OpenCode" \
  --window-pos 200 120 \
  --window-size 600 400 \
  --icon-size 100 \
  --icon "OpenCode.app" 175 190 \
  --app-drop-link 425 185 \
  "OpenCode.dmg" \
  ".build/Build/Products/Release/OpenCode.app"

Xcode Build (Alternative)

If you prefer using Xcode:

  1. Generate the project: xcodegen
  2. Open OpenCode.xcodeproj
  3. Select "OpenCode macOS" scheme
  4. Choose "My Mac" as the destination
  5. Press Cmd+R to build and run

iOS Application

CLI Build (Development)

Build for iOS simulator:

# Generate Xcode project first (if needed)
xcodegen

# Build for iOS Simulator
xcodebuild -project OpenCode.xcodeproj \
           -scheme "OpenCode iOS" \
           -configuration Debug \
           -sdk iphonesimulator \
           -derivedDataPath .build

# Install to simulator
xcrun simctl install booted .build/Build/Products/Debug-iphonesimulator/OpenCode.app

# Launch the app
xcrun simctl launch booted com.opencode.app.ios

Build for physical device:

# Build for device
xcodebuild -project OpenCode.xcodeproj \
           -scheme "OpenCode iOS" \
           -configuration Debug \
           -sdk iphoneos \
           -derivedDataPath .build \
           CODE_SIGN_IDENTITY="iPhone Developer" \
           DEVELOPMENT_TEAM="YOUR_TEAM_ID"

# Install via command line (requires device connected)
ios-deploy --bundle .build/Build/Products/Debug-iphoneos/OpenCode.app

Note: ios-deploy can be installed via Homebrew: brew install ios-deploy

CLI Build (Release)

First, create ExportOptions-iOS.plist with your team ID:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>method</key>
    <string>app-store</string>
    <key>teamID</key>
    <string>YOUR_TEAM_ID</string>
    <key>uploadSymbols</key>
    <true/>
</dict>
</plist>

For TestFlight distribution, use <string>ad-hoc</string> or <string>enterprise</string> as appropriate.

Then archive and export for App Store:

# Archive
xcodebuild -project OpenCode.xcodeproj \
           -scheme "OpenCode iOS" \
           -configuration Release \
           -sdk iphoneos \
           -derivedDataPath .build \
           archive \
           -archivePath .build/OpenCode-iOS.xcarchive

# Export for App Store
xcodebuild -exportArchive \
           -archivePath .build/OpenCode-iOS.xcarchive \
           -exportPath .build/Release \
           -exportOptionsPlist ExportOptions-iOS.plist

Upload to App Store Connect:

# Upload the IPA
xcrun altool --upload-app \
             --type ios \
             --file .build/Release/OpenCode.ipa \
             --username "YOUR_APPLE_ID" \
             --password "@keychain:AC_PASSWORD"

Xcode Build (Alternative)

If you prefer using Xcode:

  1. Generate the project: xcodegen
  2. Open OpenCode.xcodeproj
  3. Select "OpenCode iOS" scheme
  4. Choose your iOS device or simulator
  5. Press Cmd+R to build and run

Running Tests

CLI

Run all tests:

swift test

Run tests for a specific platform using xcodebuild:

# macOS tests
xcodebuild test -project OpenCode.xcodeproj \
                -scheme "OpenCode macOS" \
                -destination 'platform=macOS'

# iOS tests (simulator)
xcodebuild test -project OpenCode.xcodeproj \
                -scheme "OpenCode iOS" \
                -destination 'platform=iOS Simulator,name=iPhone 15'

Xcode

Press Cmd+U to run tests in Xcode.

Configuration

Server Connection

On first launch, configure your OpenCode server:

  1. Open the app
  2. Navigate to Settings (macOS: Cmd+,, iOS: tap gear icon)
  3. Add a new server configuration:
    • Display Name: Friendly name for your server
    • Host: Server hostname or IP address
    • Port: Server port (default: 3000)
    • Use HTTPS: Enable if server uses SSL/TLS
    • Password: Optional server password

Directory Context

Each session can be associated with a specific working directory:

  1. Create a new session
  2. Specify the directory path when prompted
  3. The app will use this directory for file operations and context

Architecture

Key Components

  • AppState: Central state management for connections, sessions, and events
  • SSEClient: Real-time event streaming from the server
  • OpenCodeAPIClient: REST API client for server communication
  • SessionTasksManager: Background task coordination
  • NotificationService: User notifications for background events

Data Models

  • ChatSession: Conversation sessions with message history
  • ServerConfiguration: Server connection settings
  • UserMessage/AssistantMessage: Message types with rich content
  • TodoTask: Task tracking with status and priority
  • PermissionRequest: File and command permission requests

Views

  • RootView: Main application entry point
  • MainNavigationView: Primary navigation and layout
  • ChatView: Message display and interaction
  • ConfigurationView: Server and settings management

Development

Project Structure

OpenCode/
├── OpenCodeApp.swift          # App entry point
├── Models/                    # Data models and types
│   ├── API/                   # API request/response types
│   ├── Parts/                 # Message part types
│   └── *.swift                # Core models
├── ViewModels/                # State management
│   ├── AppState.swift         # Main app state
│   ├── ChatViewModel.swift    # Chat logic
│   └── *.swift                # Other view models
├── Views/                     # SwiftUI views
│   ├── Chat/                  # Chat interface
│   ├── Configuration/         # Settings UI
│   ├── Screens/               # Main screens
│   └── Shared/                # Reusable components
├── Services/                  # API and services
│   ├── OpenCodeAPIClient.swift
│   ├── SSEClient.swift
│   └── *.swift
└── Utilities/                 # Helper functions

OpenCodeTests/                 # Unit tests
project.yml                    # XcodeGen project configuration
Package.swift                  # Swift Package Manager manifest

XcodeGen Configuration

The project uses project.yml to define:

  • Build settings and Swift 6 features
  • Platform-specific targets (iOS and macOS)
  • Dependencies and frameworks
  • Info.plist and entitlements
  • Test targets and schemes

To regenerate the Xcode project after modifying project.yml:

xcodegen

Code Style

This project follows standard Swift conventions:

  • Use SwiftFormat for formatting: swiftformat .
  • Use SwiftLint for linting: swiftlint
  • Follow the one-type-per-file structure (see CLAUDE.md)

Dependencies

  • EventSource: SSE client for real-time events
  • SwiftTreeSitter: Syntax tree parsing library
  • TreeSitterLanguages: Language-specific Tree-sitter grammars

Dependencies are managed via Swift Package Manager and declared in both Package.swift and project.yml.

Clean Build

If you encounter build issues:

# Clean Swift Package Manager build
rm -rf .build

# Clean derived data (if using Xcode)
rm -rf ~/Library/Developer/Xcode/DerivedData

# Regenerate Xcode project
xcodegen

# Re-resolve dependencies
swift package resolve

Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes with clear messages
  4. Push to your branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development Guidelines

  • Write tests for new functionality
  • Follow the existing code organization patterns
  • Update documentation for API changes
  • Ensure builds pass on both macOS and iOS
  • Run SwiftLint before committing
  • Regenerate the Xcode project if modifying project.yml

Troubleshooting

Connection Issues

  • Verify the server is running and accessible
  • Check firewall settings allow connections
  • Ensure the server URL and port are correct
  • Try disabling HTTPS if using a local server

Build Issues

  • Ensure XcodeGen is installed: brew install xcodegen
  • Regenerate the Xcode project: xcodegen
  • Clean build folder: rm -rf .build
  • Delete derived data: rm -rf ~/Library/Developer/Xcode/DerivedData
  • Update dependencies: swift package update
  • Ensure Xcode and Swift are up to date

Missing Xcode Project

The .xcodeproj file is not tracked in git. Generate it with:

xcodegen

Permission Issues

  • Check that the app has necessary permissions in System Settings (macOS)
  • Verify server permissions for file operations
  • Review permission prompts in the app

License

This project is licensed under the MIT License - see the LICENSE file for details.

Related Projects

  • OpenCode - The OpenCode server and CLI

Support

For issues, questions, or contributions:

  • Open an issue on GitHub
  • Check existing issues for known problems
  • Review the OpenCode server documentation for API details

About

A Swift-based OpenCode frontend for macOS and iOS

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages