Skip to content

Merge Broadway into Stuff (Shared/Broadway)#72

Merged
kyleve merged 11 commits into
mainfrom
cursor/merge-broadway
Jul 10, 2026
Merged

Merge Broadway into Stuff (Shared/Broadway)#72
kyleve merged 11 commits into
mainfrom
cursor/merge-broadway

Conversation

@kyleve

@kyleve kyleve commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Imports the Broadway design-system repo into this monorepo under Shared/Broadway/*, preserving git history, and fully wires it into the SPM/Tuist build, CI scheme, and docs.

What moved

Brought over (with history) into Shared/Broadway/:

  • BroadwayCore/ — library (BContext, traits/themes/stylesheets, utilities)
  • BroadwayUI/ — library (BRootViewController, trait-override VCs) → BroadwayCore
  • BroadwayTesting/ — UIKit test helpers → used by the hosted test bundles
  • BroadwayCatalog/ — component showcase app

Dropped as overlapping scaffolding (Stuff already has these): Broadway's Package.swift, Project.swift, Tuist.swift, ide/swiftformat/sync-agents, .mise.toml, .swiftformat, .github/, .githooks/, .agents/, LICENSE, root docs, and BroadwayTestHost/.

How history was preserved

git filter-repo rewrote the Broadway history to the final Shared/Broadway/* paths (dropping the scaffolding), then it was merged in with --allow-unrelated-histories. Broadway's original commits are now ancestors, and git log --follow traces imported files back to their Broadway history.

Wiring

  • Package.swift: added BroadwayCore, BroadwayUI (→ Core), BroadwayTesting (→ Core) products/targets.
  • Project.swift: added the BroadwayCatalog app and BroadwayCoreTests / BroadwayUITests / BroadwayCatalogTests bundles via a new broadwayUnitTests helper that links BroadwayTesting (not WhereTesting, to avoid pulling in the Where domain). All bundle IDs renamed com.broadway.*com.stuff.*. Registered in the Stuff-iOS-Tests CI scheme plus per-bundle test schemes.
  • Shared test host: BroadwayTesting.show() now finds the host window via a scene-based hostKeyWindow() (matching WhereTesting) so Broadway's hosted tests run inside StuffTestHost (which is scene-based). Renamed the misnamed XCTestCaseAdditions.swiftBroadwayTesting.swift.
  • Docs: per-module README.md + refreshed AGENTS.md, a Shared/Broadway/ group README/AGENTS, and the root AGENTS.md updated. ./sync-agents regenerated the gitignored CLAUDE.mds.

Validation (macOS)

  • ./swiftformat --lint clean (298 files)
  • tuist generate clean
  • tuist test Stuff-iOS-Tests — full suite passes, including the Broadway suites and the show()-based BRootViewControllerTests running green in StuffTestHost.

Follow-up

The old Broadway repo is retired in a companion PR that clears it and leaves a README pointing here.

Open in Web Open in Cursor 

- Add Tuist project manifest (Project.swift) and config (Tuist.swift)
- Add BroadwayCatalog SwiftUI app target (iOS + Mac Catalyst, iOS 26.0)
- Add BroadwayUI reusable framework target
- Add unit tests for both targets using Swift Testing
- Pin Tuist version via mise (.mise.toml)
- Add ide script for project generation (with optional -i for tuist install)
- Update .gitignore for Tuist/Xcode generated artifacts
- Add README.md and AGENTS.md documenting the repo

Made-with: Cursor
- Add BroadwayCore framework target with sources and tests
- BroadwayUI now depends on BroadwayCore
- Extract shared destinations/deployment into top-level constants
- Add framework() helper to eliminate target boilerplate
- Update README.md and AGENTS.md with new target and dependency graph

Made-with: Cursor
## Summary

Introduces the foundational type system for BroadwayCore, the root UIKit integration layer in BroadwayUI, and supporting test infrastructure.

### Core primitives

- **`CopyOnWrite`** — property wrapper providing value-semantic copy-on-write storage (`@_spi(CopyOnWrite)` for unsafe direct access)
- **`AnyEquatable`** — type-erased equatable box for heterogeneous containers
- **`TypeIdentifier`** — lightweight `ObjectIdentifier`-based type key with debug output
- **`EquatableIgnored`** — property wrapper that excludes a value from `Equatable` comparisons

### Environment system

- **`BAccessibility`** — snapshot of `UIAccessibility` settings with a mockable `SettingsProvider` protocol and a `@MainActor`-isolated `Observer` for live change tracking (supports `NotificationCenter` injection for testing)
- **`BTraits`** — type-keyed container for environment traits (currently holds `BAccessibility`)
- **`BThemes`** — type-keyed container for theme values conforming to `BTheme` (with `defaultValue` support)
- **`BStylesheets`** — lazy, cached stylesheet resolver with transitive dependency support, typed `StylesheetError`, and cycle detection via `defer`-based stack unwinding
- **`BContext`** — root environment container composing traits, themes, and stylesheets; updating traits/themes passes values through to the stylesheet cache
- **`BStylesheet`** / **`SlicingContext`** / **`StylesheetError`** — stylesheet protocol, creation context, and typed errors (each in their own file)

### UIKit integration

- **`BContextTrait`** — `UITraitDefinition` bridging `BContext` into `UITraitCollection` / `UIMutableTraits`
- **`BRootViewController`** — container view controller that manages `BContext`, observes accessibility changes, and propagates context via `traitOverrides`

### Test infrastructure

- **`BroadwayTesting`** — shared test utility framework with `XCTestCase` extensions (`show`, `waitFor`, `assertThrowsError`)
- **`BroadwayTestHost`** — minimal UIKit app target serving as a dedicated test host for `BroadwayCoreTests` and `BroadwayUITests`

### Tooling & CI

- **SwiftFormat** — pinned via `mise`, with `.swiftformat` config (`--extension-acl on-declarations`), `./swiftformat` runner script, CI lint gate, and auto-formatting pre-commit hook
- **CI** — `format` job (lint) + `test` job (all targets via `mise exec -- tuist test`)

### Sendable / concurrency

- `BAccessibility`, `BTraits`, `BThemes`, `BContext`, `CopyOnWrite`, `AnyEquatable`, `TypeIdentifier` all conform to `Sendable` (some `@unchecked` where `AnyHashable` storage prevents automatic inference)
- `BAccessibility.Observer` and `BRootViewController` are `@MainActor`-isolated

## Test coverage

~100 test cases across 11 test files covering all new types, including stylesheet dependency chains, cycle detection, observer lifecycle, accessibility mocking, and hosted UI tests.

## Stats

38 files changed, ~2,600 lines added
## Summary

Adds a `sync-agents` script (Ruby) that keeps AI agent configuration in sync across Cursor, Codex, and Claude Code from a single source of truth (`AGENTS.md` files and `.agents/skills/`).

**What it does:**

- Generates `CLAUDE.md` from each `AGENTS.md` (Cursor and Codex read `AGENTS.md` natively).
- Syncs `.agents/skills/` to `.claude/skills/` for Claude Code.
- Manages external skills from GitHub repos, pinned to commit SHAs via `.agents/external-skills.json`.
- Runs incrementally — skips files already up to date.

**Commands:**

- `./sync-agents` — generate CLAUDE.md files and sync skills
- `./sync-agents --add <url> [name]` — add an external skill from GitHub, pinned to the current commit
- `./sync-agents --install` — fetch all external skills from the manifest (skips if present)
- `./sync-agents --update` — re-fetch all external skills at latest commit
- `./sync-agents --git-add` — sync + stage changed files (used by pre-commit hook)

**Other changes:**

- Simplify root `AGENTS.md` and `README.md`; move module-specific details into nested `AGENTS.md` files for BroadwayCore, BroadwayUI, and BroadwayCatalog.
- Remove `Plans/` directory.
- Add convention: shell scripts > ~20 lines should use Ruby.
- Generated files (`CLAUDE.md`, `.claude/skills/`, external skills) are gitignored. `./ide` runs `./sync-agents --install` to populate them on setup.
- Pre-commit hook runs `./sync-agents --git-add` and SwiftFormat automatically.
- Install SwiftUI Pro skill from twostraws/swiftui-agent-skill as first external skill.
## Summary

- **Unified trait observation:** `BTraitsValue` declares an `Observer` associated type conforming to `BTraitsValueObserver`. `BTraitsObserver` coordinates per-type observers from `BTraits` registrations, using `currentValue(from:)` and `makeObserver(with:onChange:)`, with **idempotent** `start()` / `stop()` at the coordinator.
- **Explicit observers:** Every `BTraitsValue` implements `makeObserver` (no protocol default). `NeverObserver` remains available for traits with nothing live to subscribe to.
- **`BTraits` registration:** `.system`, `register(_:)`, and `readCurrentValues(from:)` centralize which types participate.
- **`BContext`:** Separates `baseTraits` and subtree `traitOverrides`; merged `traits` drives equality and **stylesheet config**. `BStylesheets` keeps **private** trait/theme storage; `BContext` syncs via `updateTraits` / `updateThemes` (package-visible from the Swift package boundary).
- **`BRootViewController`:** Lazy setup in `viewIsAppearing`; one `BTraitsObserver(traits: .system, from: self)` replaces ad hoc accessibility wiring.
- **`BTraitOverridesViewController`:** Applies overrides from the **full inherited** context (parent `traitCollection.bContext` when embedded); refreshes in **`didMove(toParent:)`** and on trait changes; child creation still deferred to `viewIsAppearing`.
- **UIKit / SwiftUI:** Trait bridging (`BMode`, `BContentSizeCategory`, `UIViewControllerTraitObserver`), SwiftUI environment and modifiers for `BContext` / overrides.
- **`BAccessibility.Observer`:** Internal initializer only (no public `observe` factory); review chose to keep construction package-internal until a public API is needed.
- **Build layout:** Root **`Package.swift`** ships **BroadwayCore**, **BroadwayUI**, and **BroadwayTesting** (sources under `*/Sources`). **Tuist** generates the Xcode workspace for **BroadwayCatalog**, **BroadwayTestHost**, and **`.xctest`** bundles that depend on those products. **BroadwayTesting** in SPM links UIKit only (no `.xctest` link on the library); see `Project.swift` comment near the local package.
- **Concurrency:** `Sendable` / `@unchecked Sendable` where required for Swift 6 (e.g. `BMode`, `BContentSizeCategory`, `SettingsProvider` usage).
- **Docs:** `AGENTS.md` / `README.md` describe hybrid SPM + Tuist workflows and how to run tests.
Pure-formatting step (no behavior change): the imported tree shipped Broadway's own .swiftformat, which was dropped in the move. Reformat under Stuff's .swiftformat so ./swiftformat --lint passes.
Wire BroadwayCore, BroadwayUI (->Core), and BroadwayTesting (->Core) as package products/targets under Shared/Broadway/*. Not yet referenced by any Tuist target, so existing targets are unaffected.
Add the BroadwayCatalog app, BroadwayCore/UI/Catalog test bundles (com.stuff.* IDs) via a broadwayUnitTests helper that links BroadwayTesting instead of WhereTesting, and register them in the Stuff-iOS-Tests scheme plus per-bundle test schemes.

Retarget BroadwayTesting.show() to a scene-based hostKeyWindow() lookup so its hosted tests run inside the shared, scene-based StuffTestHost (its window lives on the UIWindowSceneDelegate, not the app delegate). Rename the misnamed XCTestCaseAdditions.swift (no XCTest) to BroadwayTesting.swift.
Add per-module README.md for BroadwayCore/UI/Testing/Catalog plus a Shared/Broadway group README/AGENTS, refresh the module AGENTS.md files to Stuff's convention (link back to root + group, invariants, testing pointer), and list the Broadway modules/targets in the root AGENTS.md. CLAUDE.md files are regenerated by ./sync-agents (gitignored).
@kyleve kyleve marked this pull request as ready for review July 10, 2026 17:51
@kyleve kyleve merged commit fa14a8a into main Jul 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant