twostraws/ControlRoom
A macOS app to control the Xcode Simulator.
Healthy across the board
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 5w ago
- ✓18 active contributors
- ✓Distributed ownership (top contributor 44% of recent commits)
Show 3 more →Show less
- ✓MIT licensed
- ✓CI configured
- ⚠No test directory detected
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/twostraws/controlroom)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/twostraws/controlroom on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: twostraws/ControlRoom
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/twostraws/ControlRoom shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 5w ago
- 18 active contributors
- Distributed ownership (top contributor 44% of recent commits)
- MIT licensed
- CI configured
- ⚠ No test directory detected
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live twostraws/ControlRoom
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/twostraws/ControlRoom.
What it runs against: a local clone of twostraws/ControlRoom — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in twostraws/ControlRoom | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | Last commit ≤ 65 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of twostraws/ControlRoom. If you don't
# have one yet, run these first:
#
# git clone https://github.com/twostraws/ControlRoom.git
# cd ControlRoom
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of twostraws/ControlRoom and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "twostraws/ControlRoom(\\.git)?\\b" \\
&& ok "origin remote is twostraws/ControlRoom" \\
|| miss "origin remote is not twostraws/ControlRoom (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 65 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~35d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/twostraws/ControlRoom"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Control Room is a native macOS app that wraps Apple's simctl command-line tool to provide a graphical UI for controlling iOS, tvOS, and watchOS simulators. It lets developers interactively adjust simulator state (time, location, battery, WiFi, Dark Mode, accessibility settings), take screenshots with device bezels, send push notifications, trigger deep links, and manage installed apps—all without CLI commands. Single-app structure: ControlRoom/ root contains SwiftUI views (About UI/), Controllers/ with domain logic (SimCtl.swift as the main simctl wrapper, Simulator.swift for model, SimulatorsController.swift for orchestration), Chrome rendering for device bezels, and preference management. Assets.xcassets/ holds app icons and resources. .xcodeproj/ manages the Xcode build.
👥Who it's for
iOS/tvOS/watchOS developers using Xcode who want a faster, more visual alternative to simctl commands for simulator configuration and testing during development. Secondary users: QA testers validating app behavior under different device conditions.
🌱Maturity & risk
Actively maintained and production-ready. Written in SwiftUI (Swift 5.8+), targets macOS 13+, has CI via GitHub Actions (see .github/workflows/ci.yml), includes SwiftLint enforcement (.swiftlint.yml), and is authored by Paul Hudson (established Swift educator). No visible test suite, suggesting light testing infrastructure, but the single-file simctl wrapper and long-running project history indicate stability.
Low risk for core stability; main concerns are (1) hard dependency on Xcode and simctl availability on the user's system with no fallback, (2) single primary maintainer (Paul Hudson / twostraws) with unknown backup, (3) no visible automated test coverage means refactors could break simulator interaction without detection, (4) reliance on undocumented simctl behavior that Apple could change between Xcode versions.
Active areas of work
No specific recent changes visible in the file list, but the presence of Release and Debug schemes in .xcschemes/ and active CI configuration suggests ongoing maintenance. The repo accepts contributions (see CODE_OF_CONDUCT.md) and explicitly calls for error handling improvements and documentation in the README.
🚀Get running
Clone and build in Xcode:
git clone https://github.com/twostraws/ControlRoom.git
cd ControlRoom
open ControlRoom.xcodeproj
Then select the 'Release - ControlRoom' or 'Debug - ControlRoom' scheme and press ⌘B to build. Requires Xcode 14.0+, macOS 13+, and simctl in your Xcode Command Line Tools.
Daily commands: Open ControlRoom.xcodeproj in Xcode and press ⌘R to run. Alternatively, build via scheme:
xcodebuild -scheme 'Debug - ControlRoom' build
The app runs as a native macOS application and connects to locally running Xcode simulators.
🗺️Map of the codebase
- ControlRoom/Controllers/SimCtl.swift: Core wrapper around Apple's simctl command-line tool; all simulator state changes route through here via Process execution
- ControlRoom/Controllers/Simulator.swift: Data model representing a single simulator instance with properties (name, state, available devices); decoded from simctl JSON output
- ControlRoom/Controllers/SimulatorsController.swift: Main orchestrator that fetches simulators, manages app lifecycle, and coordinates state updates across the UI
- ControlRoom/ControlRoomApp.swift: SwiftUI app entry point; defines window structure and top-level navigation
- ControlRoom/Controllers/ChromeRendering/ChromeRenderer.swift: Handles rendering device bezels around screenshots; optional visual enhancement for screenshot export
- .swiftlint.yml: Enforces Swift style rules; PRs must pass SwiftLint with zero errors/warnings before merge
🛠️How to make changes
Start in ControlRoom/Controllers/: SimCtl.swift is the command wrapper (add new simctl subcommands here), Simulator.swift defines the data model (add fields here for new simulator state), SimulatorsController.swift orchestrates fetching simulators. For UI changes, explore ControlRoom/ for SwiftUI views. Add tests in a Tests/ folder (currently missing). See .swiftlint.yml for code style rules before submitting PRs.
🪤Traps & gotchas
- Xcode Command Line Tools path: app requires simctl binary from Xcode CLT; if not set, silent failure. Verify via Xcode > Preferences > Locations > Command Line Tools. 2. Simulator state coupling: simctl output format changes between Xcode versions can break parsing; test against multiple Xcode versions. 3. No test suite: UI and simctl integration are untested; manual testing required for all changes. 4. Process execution delays: simctl commands are synchronous Process calls (blocking); long-running operations (screenshot, install app) can freeze the UI if not handled in background threads.
💡Concepts to learn
- Process execution and standard output parsing — SimCtl.swift executes simctl as a subprocess and parses JSON/text output; understanding Process, Pipe, and JSONDecoder is critical to extending simulator control
- SwiftUI state management and ObservableObject — Controllers use @Published properties to drive UI reactivity; understanding the pub/sub pattern is essential to modifying how UI reacts to simulator state changes
- Codable and JSON decoding — Simulator data (devices, apps, status) comes from simctl JSON output; Codable/JSONDecoder is used to map JSON to Swift models like Simulator and Application
- NSImage rendering and rasterization — ChromeRenderer composites simulator screenshots with device bezels using Core Graphics/NSImage; critical for screenshot export feature
- User defaults and preference persistence — Controllers/Preferences.swift manages user settings (recent deep links, color history); UserDefaults is the backing store for app configuration state
- macOS menu bar and status items — App supports optional menu bar icon with quick actions (resend push, reopen deep link); NSStatusBar integration is non-obvious in SwiftUI
- Simctl command-line interface and xcode-select — Control Room is a graphical wrapper around Apple's simctl; understanding simctl subcommands (list, boot, install, push, etc.) and xcode-select is foundational
🔗Related repos
wix/AppleSimulatorUtils— Direct alternative: Objective-C wrapper around simctl with similar goals (control simulators programmatically), useful for understanding the simctl API surfaceIBM-Swift/Swift-Kuery— Not directly related but shows another large Swift macOS project structure; useful for architectural patterns in Swift-only appsrealm/realm-swift— Popular Swift library; Control Room could benefit from SwiftUI bindings to Realm for persistent state (screenshots, deep links, preferences)pointfreeco/swift-composable-architecture— Modern Swift async/reactive pattern (TCA); Control Room's state management could migrate from imperative Controllers to TCA for testability and claritytwostraws/HackingWithSwift— Companion repo by same author (Paul Hudson) documenting Swift concepts; useful for understanding design philosophy and community contribution standards in the twostraws org
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add unit tests for SimCtl command execution and parsing
The SimCtl.swift file wraps Apple's simctl command-line tool, which is critical to ControlRoom's functionality. Currently, there are no visible test files in the repository structure. Adding unit tests for SimCtl+Commands.swift and SimCtl+Types.swift would ensure command parsing, error handling, and simulator state changes are reliable and prevent regressions during refactoring.
- [ ] Create Tests/ControlRoomTests/ directory structure
- [ ] Add unit tests for SimCtl.swift focusing on command execution mocking
- [ ] Add unit tests for SimCtl+Types.swift to verify JSON parsing of simulator state
- [ ] Add unit tests for SimCtl+SubCommands.swift to validate command string construction
- [ ] Configure test targets in ControlRoom.xcodeproj/project.pbxproj
- [ ] Update CI workflow in .github/workflows/ci.yml to run tests
Add comprehensive documentation for DeepLinksController and DeepLink helpers
The DeepLink feature (Controllers/DeepLinksController.swift and Helpers/DeepLink.swift) appears to be a significant feature enabling deep linking into simulators, but there is no dedicated documentation or code comments explaining how to use it or extend it. Contributing developers need guidance on the supported deep link formats and implementation details.
- [ ] Create DEEPLINKS.md in the repo root documenting supported deep link formats
- [ ] Add inline documentation comments to DeepLink.swift explaining the parsing logic
- [ ] Add inline documentation comments to DeepLinksController.swift explaining the execution flow
- [ ] Document how to add support for new deep link types with examples
- [ ] Update README.md with a link to DEEPLINKS.md in the Features section
Refactor ChromeRendering module with unit tests for screenshot chrome rendering
The ChromeRendering directory (ChromeRenderer.swift and ChromeRendererTypes.swift) handles device frame rendering for screenshots—a complex visual feature. Currently, there are no visible tests, and the module lacks documentation on how the rendering pipeline works. Adding tests would ensure frame rendering works across different device types and prevent visual regressions.
- [ ] Create Tests/ChromeRenderingTests/ChromeRendererTests.swift
- [ ] Add unit tests for ChromeRenderer.swift covering different device types (iPhone, iPad, Apple Watch, Apple TV)
- [ ] Add snapshot tests using a lightweight approach (e.g., comparing rendered image dimensions and color properties)
- [ ] Document the chrome rendering pipeline in ChromeRenderer.swift with detailed comments
- [ ] Add ChromeRendering.md documentation explaining supported devices and frame styles
- [ ] Update .swiftlint.yml if needed to enforce documentation standards for this module
🌿Good first issues
- Add a test suite for SimCtl.swift simctl command parsing (e.g., mock JSON responses from
xcrun simctl list --jsonand verify Simulator/Application decoding). Currently zero test coverage for the core wrapper. - Improve error messages in Controllers/: many simctl calls lack user-friendly error handling. Pick one controller (e.g., LocationsController.swift or PushNotification.swift) and add descriptive alerts when simctl fails, rather than silent failures.
- Document the Simulator model fields and SimCtl command signatures in code comments or a CONTRIBUTING.md. New contributors can't tell which simctl subcommands are wrapped or why certain Simulator properties exist.
⭐Top contributors
Click to expand
Top contributors
- @twostraws — 44 commits
- @Harry-KNIGHT — 10 commits
- @MultiColourPixel — 9 commits
- @AlexChekel1337 — 6 commits
- [@John McEvoy](https://github.com/John McEvoy) — 5 commits
📝Recent commits
Click to expand
Recent commits
c8c7d4c— Merge pull request #206 from Jack-sh1/fix/swift6-concurrency-and-retroactive-conformance (twostraws)f046456— Fix Swift 6 concurrency warnings and retroactive conformance (#199) (Jack-sh1)afc95ae— Merge pull request #204 from PerlBeforeSwine/fix/swiftlint_issues (twostraws)8ef61cd— Update identifier names to camelcase for convention (PerlBeforeSwine)204cbee— Fixed linter errors, warnings, and rule definition (PerlBeforeSwine)327e37e— Merge pull request #200 from sbeitzel/feature/suppress_linting (twostraws)e683014— Merge branch 'main' into feature/suppress_linting (sbeitzel)f7a1c5c— Merge pull request #198 from sbeitzel/feature/redundant_initializer (twostraws)fe49915— Merge branch 'main' into feature/redundant_initializer (twostraws)2486a51— Merge pull request #197 from sbeitzel/feature/clean_linter_warnings (twostraws)
🔒Security observations
Failed to generate security analysis.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.