This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Wammer is a fork of MUDRammer, an Objective-C iOS MUD client. The codebase has been modernized from CocoaPods to vendored Swift packages and from a hand-maintained Xcode project to Tuist-generated workspaces. Targets iOS 26.
The project uses Tuist (v4.131.0) to generate the Xcode workspace from Project.swift and Tuist.swift.
tuist generate # Generate Wammer.xcworkspaceBuild and run from the generated Wammer.xcworkspace using the Wammer scheme.
xcodebuild test \
-workspace Wammer.xcworkspace \
-scheme MRTests \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro'Test target is MRTests (defined in Project.swift). Tests use Expecta (assertions) and OCMock.
CLANG_ENABLE_MODULES=YESis required for@importsyntax in ObjCGCC_PREFIX_HEADERpoints tosrc/Mudrammer/Supporting Files/Mudrammer-Prefix.pch(app) andsrc/MRTests/MRTests-Prefix.pch(tests)HEADER_SEARCH_PATHSincludes$(SRCROOT)/Vendored/**and$(SRCROOT)/src/Mudrammer/**- All vendored packages use
swift-tools-version: 6.2with.iOS(.v26)
All app source is under src/Mudrammer/. Tests are in src/MRTests/.
- Network/ — Telnet/ANSI networking stack. Data flows: socket →
SPLTelnetLib(telnet protocol + zlib) →SSANSIEngine(ANSI → NSAttributedString) →SSMUDSocket(delivers attributed line groups to UI) - Models/ — Currently empty; legacy Core Data models have been removed.
- WorldStore/ — Swift Codable models (
MUDWorld,MUDAlias,MUDTrigger,MUDGag,MUDTickerinModels.swift) with JSON flat-file persistence (WorldStore.swift). Business logic inModels+Logic.swift. ObjC bridging viaWorldStoreBridge.swiftand the auto-generatedWammer-Swift.h. - Controllers/Client/ — Active MUD session UI:
SSClientViewController(terminal),SSSessionLogger(transcripts),SPLWorldTickerManager(periodic commands) - Controllers/Settings/ — World list, world editor, theme/sound/encoding pickers
- Forms/ — QuickDialog/FXForms-based editors for aliases, triggers, gags, tickers
- Views/ —
SSMudView(terminal display),SSGrowingTextView(input),SSTextTableView(scrollback) - Additions/ — Category extensions on Foundation/UIKit classes
All former CocoaPods are vendored as local Swift packages in Vendored/. Key ones:
- CocoaAsyncSocket — TCP socket library
- libtelnet — Telnet protocol primitives (C library)
- SPLCore — Shared utilities (depends on libextobjc)
- JASidePanels — Side panel navigation
- Masonry — Auto Layout DSL
- TTTAttributedLabel — Rich text display
World data is stored as JSON in Documents/worlds.json via WorldStore (singleton). No Core Data or MagicalRecord — all models are Swift Codable classes with @objc/@objcMembers for ObjC interop. Default worlds loaded from DefaultWorlds.plist on first launch.
Swift → ObjC: The auto-generated Wammer-Swift.h works and contains all @objc classes. ObjC files import #import "Wammer-Swift.h" to use Swift types.
ObjC → Swift: A bridging header at src/Mudrammer/Supporting Files/Wammer-Bridging-Header.h exposes ObjC types to Swift. Some ObjC headers that use @import for vendored SPM packages can't be imported directly in the bridging header — use forward declarations instead.
Swift classes use @objc(ClassName) and @objcMembers for ObjC interop. New Swift code should be written in Swift; avoid adding new ObjC classes.
The app uses the UIScene lifecycle for multi-window support on iPad and Mac Catalyst. Each window gets its own WammerSceneDelegate (Swift) which creates an independent SSClientContainer as root. There is no singleton container — view controllers find their container via the UIViewController(SSClientContainerAccess) category (self.clientContainer / self.worldDisplay). Menu bar actions are on SSClientContainer and route through the responder chain to the focused window.
SSMUDSocketopens TCP connection via CocoaAsyncSocket- Raw data passes through
SPLTelnetLibfor telnet negotiation and optional zlib decompression SSStringCoderhandles character encoding conversionSSANSIEngineparses ANSI escape codes intoNSAttributedStringSSAttributedLineGroupbatches attributed strings for displaySSMudView/SSTextTableViewrenders the output
- Do not add file header comments (the
// Filename.m // ProjectName //block) to new files.
- Avoid singletons. They cause problems with multi-window and multi-connection architecture. Per-connection state should be owned by
SSClientViewController. Always consider ownership and lifecycle before reaching for a singleton — they're rarely the right choice.
- Main branch:
trunk