How to Contribute to the vphone-cli Project: A Complete Developer Guide
To contribute to vphone-cli, fork the repository with submodules, configure the Swift 6.0 development environment using the provided automation scripts, and submit pull requests that include unit tests and follow the project's formatting standards.
vphone-cli is a Swift 6.0 command-line tool that boots a virtual iPhone on Apple Silicon by leveraging the private PV = 3 entitlements of Virtualization.framework. Understanding how to contribute to vphone-cli requires familiarity with its multi-layered architecture spanning CLI parsing, VM lifecycle management, and binary firmware patching.
System Requirements and Prerequisites
Contributing to vphone-cli demands specific hardware and software configurations. You must run macOS 15 or later on Apple Silicon to utilize the required Virtualization.framework APIs.
Install the host dependencies using Homebrew before proceeding:
brew install python@3.13 ldid-procursus keystone
The firmware patcher relies on Capstone for disassembly, Keystone for re-assembly, and pyimg4 for IM4P blob manipulation. These tools bundle automatically into a Python virtual environment via the provided setup scripts.
Setting Up the Development Environment
Begin by forking the repository and cloning it with submodules to ensure you capture all dependencies:
git clone --recurse-submodules https://github.com/<your-username>/vphone-cli.git
cd vphone-cli
Bootstrap the toolchain and build environment by executing the automation scripts located in scripts/:
./scripts/setup_tools.sh # Installs sub-module toolchains and creates .venv
./scripts/build.sh # Builds, signs, and bundles the .app
Verify your baseline is clean by running the comprehensive test suite:
make test # Swift unit tests via Package.swift
./scripts/run_firmware_tests.sh # Python firmware-patch validation
Understanding the vphone-cli Architecture
The codebase organizes functionality into four distinct layers. Knowing these boundaries helps you locate where to implement new features when you contribute to vphone-cli.
Command-Line Interface Layer
The CLI layer parses arguments and dispatches sub-commands. Core files include main.swift, VPhoneCLI.swift, and VPhoneVMCLI.swift, alongside concrete implementations like VPhoneVMCreateCLI.swift and VPhoneFWCLI.swift.
Virtual Machine Core
This layer constructs the VZVirtualMachineConfiguration and manages hardware models. Key files are VPhoneVirtualMachine.swift, VPhoneHardwareModel.swift, and VPhoneWindowController.swift.
Guest-Side Integration
The host communicates with the in-VM daemon (vphoned) via a vsock JSON protocol. Files such as VPhoneControl.swift, VPhoneMenuController.swift, and VPhoneFileBrowserModel.swift handle UI menus, file browsing, and IPA installation.
Firmware Patcher
Located under sources/FirmwarePatcher/, this component performs binary-level transformations for firmware variants (less, regular, dev, jb, exp). The pipeline orchestrates through FirmwarePipeline.swift and specialized classes like KernelJBPatcherBase.swift.
Contribution Areas and Implementation Patterns
When planning your vphone-cli contribution, focus on these high-impact areas:
Adding New CLI Sub-commands
Create a new Swift file under sources/vphone-cli/ conforming to the ArgumentParser protocol. Reference VPhoneVMCreateCLI.swift for the established pattern.
Example implementation of a ping command:
// sources/vphone-cli/VPhonePingCLI.swift
import ArgumentParser
struct VPhonePingCLI: ParsableCommand {
static var configuration = CommandConfiguration(
commandName: "ping",
abstract: "Send a ping to the running VM's guest daemon."
)
@Option(name: .shortAndLong, help: "Name of the VM to ping.")
var vm: String
func run() throws {
let ctrl = try VPhoneControl(vmName: vm) // Reference: VPhoneControl.swift
let resp = try ctrl.send(command: "ping", payload: [:])
print("Response:", resp)
}
}
Register the command in VPhoneCLI.swift by adding it to the subcommands array.
Extending Menu Functionality
For UI enhancements, create a new VPhoneMenu* class and register it in VPhoneMenuController.swift:
// sources/vphone-cli/VPhoneMenuDiagnostics.swift
import Cocoa
final class VPhoneMenuDiagnostics: NSObject {
@objc func showDiagnostics(_ sender: Any?) {
VPhoneVirtualMachine.shared?.dumpInfo()
}
}
Hook the menu item in VPhoneMenuController.swift:
func setupMenus() {
let diagItem = NSMenuItem(title: "Diagnostics", action: #selector(VPhoneMenuDiagnostics.showDiagnostics), keyEquivalent: "")
menu.addItem(diagItem)
}
Firmware Patching
To add new kernel patches, extend FirmwarePipeline.swift or create a new Kernel*Patcher class following the style in KernelJBPatcherBase.swift. Consult research/0_binary_patch_comparison.md for detailed variant specifications.
Documentation Improvements
Enhance README sections, add language-specific guides, or expand the research/ markdown files with technical deep-dives.
Code Style and Standards
The project enforces consistency through SwiftPM formatting (swift format). Adhere to these conventions:
- Keep changes minimal and focused
- Add
// MARK:sections for new logic blocks - Prefer
privateaccess modifiers where possible - Follow the conventions documented in
AGENTS.md
Testing Requirements
Every contribution must include comprehensive test coverage. For Swift code, use XCTest and place test files adjacent to implementations (e.g., VPhoneMenuRecordTests.swift alongside VPhoneMenuRecord.swift). For firmware modifications, provide pytest validation scripts.
Run the full test matrix locally before submission to ensure compatibility with the CI pipeline running on macOS 15.
Submitting Your Contribution
Push your feature branch to your fork and open a pull request against the main repository. Reference related issues in your PR description. The CI system will execute the complete test suite including Swift unit tests and Python firmware validation. All checks must pass before maintainers can merge your code.
Summary
- Fork and clone with
--recurse-submodulesto capture all dependencies - Run setup scripts (
setup_tools.shandbuild.sh) to configure the Swift 6.0 environment - Understand the four layers: CLI interface, VM core, guest integration, and firmware patching
- Follow patterns: Use
ArgumentParserfor commands,VPhoneMenuControllerfor UI, andFirmwarePipelinefor binary patches - Maintain quality: Apply
swift format, add// MARK:labels, and include unit tests - Verify locally: Execute
make testand firmware tests before submitting PRs
Frequently Asked Questions
What programming languages does vphone-cli use?
vphone-cli is primarily written in Swift 6.0 for the CLI and VM management components. The firmware patcher uses Python with Capstone and Keystone engines for binary transformation. You should be comfortable with both languages to contribute across all subsystems.
Do I need special entitlements to test vphone-cli locally?
Yes. Testing the full virtualization features requires macOS 15+ on Apple Silicon hardware and the private PV = 3 entitlements for Virtualization.framework. The build scripts handle code signing automatically, but you must run the software on compatible hardware to validate VM functionality.
Where should I add tests for new firmware patches?
Add Python tests in the tests/ directory corresponding to the firmware patcher components. For a new Kernel*Patcher class, create parallel test files that validate the binary transformations against known good firmware images. Run these via ./scripts/run_firmware_tests.sh.
Can I contribute documentation without coding?
Absolutely. The research/ directory contains markdown files detailing binary patch comparisons and technical architecture. Improving README sections, adding usage examples, or creating troubleshooting guides in the documentation are valuable contributions that do not require Swift or Python development.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →