Architecture
Engineering notes for chandram-dutta/sochi. Swift 6, macOS 14+, ArgumentParser CLI + SochiKit library.
Package
Section titled “Package”| Target | Role |
|---|---|
sochi |
CLI: Sochi.swift, Commands.swift, EditCommands.swift, Terminal.swift, Version.swift |
SochiKit |
Domain logic |
SochiKitTests |
Swift Testing; many suites need a real Xcode |
Dependency: apple/swift-argument-parser ≥ 1.5.0. sochiVersion is "dev" from source; release builds stamp it from the tag.
Design invariants
Section titled “Design invariants”- No hand-maintained Apple catalogs — capabilities, product types, and templates are loaded from the selected Xcode.
- Remembered values are choices only (scheme, team). Build settings are always queried fresh.
- Edits are planned, shown as diffs, applied atomically, verified, rolled back on failure.
- Projects with XcodeGen/Tuist markers are refused unless
--force. - CLI status goes to stderr so
runcan leave app stdout clean for pipes.
Runtime hub: Session
Section titled “Runtime hub: Session”Used by run / build:
XcodeProject.locate→ loadProjectState- Scheme: explicit → saved →
Xcodebuild.pickScheme - Destination: physical device by default;
--simor named simulator - Team:
--team/SOCHI_TEAM/ saved / recovery on signing failure buildResolving:xcodebuildinto sochi DerivedData;BuildLogevents; one retry on recoverable scheme/team errors- Persist successful choices;
prepare(boot sim) +appProduct(-showBuildSettings) AppBundle.verify→installIfNeeded(device fingerprint skip unless--fresh) →launchAttached
Edit hub: EditPlan + ProjectEditor.apply
Section titled “Edit hub: EditPlan + ProjectEditor.apply”add / remove / entitlements call ProjectEditor.plan*. Plans read resolved entitlements / Info.plist paths from xcodebuild settings (not guessed only from pbxproj). Apply: atomic file writes → re-parse / settings checks → rollback all files on failure.
Important types
Section titled “Important types”CapabilityCatalog/CapabilityWriter— portal JSON from Xcode; local capabilities (e.g. Background Modes → Info.plist)EntitlementSchema— allowed keys/types from Xcode schemasPBXProjectFile/PBXTextWriter—project.pbxprojmutationXcodeSpecs— product types, embed rules from.xcspecTemplateIndex/TemplateEngine/TargetBuilder—.xctemplateinstantiationMigration/MigrationVerifier/Reorganizer— groups → synchronized folders; optional file moves
Target add assumes folder-based projects (objectVersion ≥ 77). Use migrate on classic group projects.
new and migrate
Section titled “new and migrate”new:ProjectCreator→ template instantiate → skeleton pbxproj →TargetBuilder→xcodebuild -listverify; delete tree on failure. Remembers--org.migrate:Migration.plan→ optional before/afterBuildInventorycompare → apply.--move-filesrunsReorganizerthen convert.
State paths
Section titled “State paths”| Data | Path |
|---|---|
| DerivedData | ~/Library/Caches/dev.sochi/projects/<name>-<fnv1a>/DerivedData |
state.json (scheme, team, installs) |
~/Library/Application Support/dev.sochi/projects/<id>/ |
Module sketch
Section titled “Module sketch”CLI SochiKit───────────────────── ────────────────────────────────SessionOptions / Run → Session → Xcodebuild / BuildLog Devices | Simulators | Signing | AppBundleEditCommands.runPlan → ProjectEditor.plan* → apply CapabilityCatalog | TemplateEngine | PBX*New → ProjectCreatorMigrate → Migration | Reorganizer | MigrationVerifier ▲ selected Xcode (catalogs, specs, templates)Contributors
Section titled “Contributors”- Domain changes go in SochiKit; wire flags in
Commands.swift/EditCommands.swift. - Prefer extending Xcode data loaders over hardcoding Apple lists.
- Tests/goldens:
Fixtures/Golden/Xcode-27.0/,Fixtures/Classicfor migration. - Local release dry-run:
scripts/build-release.sh 0.1.0→dist/. Script must leaveVersion.swiftas"dev". - Published releases: GitHub tag → workflow builds universal tarball + checksum → updates
Formula/sochi.rb.