This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
CornucopiaCore is a Swift Package Manager library providing essential utilities for Swift developers across Apple platforms (iOS 14+, macOS 12+, tvOS 14+, watchOS 8+). It's a collection of extensions, utilities, and helper classes designed to augment Foundation and platform-specific frameworks.
This project uses Swift Package Manager with the following commands:
- Build:
swift build - Test:
swift test - Clean:
swift package clean
The project targets Swift 5.10+ and has continuous integration via GitHub Actions that runs on both Ubuntu and macOS.
The project has two external dependencies:
swift-crypto(3.0.0+): Apple's cryptographic libraryAnyCodable(0.6.6+): Type-erased Codable support (re-exported at module level)
The main module CornucopiaCore is organized into several logical groups:
All public APIs are nested under Cornucopia.Core namespace. The main entry point is Sources/CornucopiaCore/CornucopiaCore.swift which defines the namespace and re-exports AnyCodable.
-
Extensions (
Extensions/): Platform and Foundation type extensions- Organized by type (Array, String, Data, etc.)
- Follow
CC_prefix convention for public methods - Cover networking, data manipulation, validation, and utility functions
-
Features (
Features/): Standalone functionality modulesDeviceInfo: Cross-platform device identification with UUID persistenceJWT: JSON Web Token supportBenchmarking: Performance measurement utilitiesConcurrency: Async/await utilities and timeout mechanismsEnvironment: Environment variable handling
-
Logging (
Logging/): Flexible logging systemLogger: Main logging interface with configurable sinks- Supports multiple output targets (print, syslog, file, OSLog, ring buffer)
- Environment/UserDefaults configurable via
LOGLEVELandLOGSINK - Thread-safe with background dispatch queue (
Logger.dispatchQueue); all sink calls arrive serially on that queue — sinks can rely on this for confinement RingBufferLogger("flight recorder"): buffers entries in RAM only and replays them to a target sink on demand. Use it when logging I/O would perturb or hide timing-sensitive bugs, or in release builds to retrieve the recent past after a problem was observed. Configure viaLOGSINK=ring://?capacity=65536&keep=30&target=<percent-encoded sink url>&autodump=error&signal=USR1(plusLOGLEVEL=TRACEso entries reach the buffer). Triggers:Logger.ringBuffer?.dump(last:)from code,signal=USR1in the URL (orinstallTrigger(signal:)from code) +kill -USR1 <pid>from outside, orautodump=error|faultfor automatic flushing. Without atarget, dumps go to a timestampedlogdump-*.login Caches. In tests, synchronize withwaitUntilDumped()— never with sleeps
-
PropertyWrappers (
PropertyWrappers/): Utility property wrappers@Default: Codable with default values@Clamped: Value constraints@HexEncoded: Automatic hex encoding/decoding@Protected: Thread-safe property access
-
Storage (
Storage/): Data persistence abstractionsKeychain: Secure storage interfaceExtendedFileAttributes: File metadata handling- Storage backend protocol for pluggable backends
- Public extension methods use
CC_prefix - Internal static constants use descriptive names
- Property wrappers follow Swift conventions
- Logger categories derived from
#fileIDby default
The codebase includes extensive platform-specific compilation conditions:
#if canImport(ObjectiveC)for Apple vs. Linux differentiation- Platform-specific imports (
UIKit,WatchKit, etc.) - Conditional feature availability (syslog not available on watchOS)
- Architecture-specific code paths in DeviceInfo
Tests mirror the source structure under Tests/CornucopiaCoreTests/ and cover:
- Extension functionality
- Property wrapper behavior
- Core features like logging and device info
- Cross-platform compatibility
Reliability rules for logging tests (output-based tests have proven flaky here):
- Never assert on captured stdout/stderr — feed entries into an in-memory recording
sink and assert on its collected
LogEntryvalues instead - Never synchronize with sleeps — feed entries via
Logger.dispatchQueue.sync(the production path) and useRingBufferLogger.waitUntilDumped()after dumps - Avoid the global
Logger.destination/overrideSinkstatic state in tests; instantiate sinks directly so tests stay order-independent - When testing signal delivery, use process-directed
kill(getpid(), SIG…), notraise()— the latter targets the calling thread, which may block the signal under XCTest; also keep re-sending in a poll loop, since dispatch signal sources register asynchronously and an early one-shot signal can get lost
- All files include copyright header:
// Cornucopia – (C) Dr. Lauer Information Technology - Extensions are organized by the type they extend
- Comprehensive
#ifconditions ensure cross-platform compatibility - Property wrappers follow Codable protocols where applicable
- Logger uses background queue for thread safety