A Claude Code skill that scaffolds a cross-platform
C++ SDK with a stable C-ABI boundary, wrapped as an Apple XCFramework
and consumable from Swift — built so the same compiled core can later serve
an Android .aar or Windows .dll client without touching the core.
It generates a compile-verified skeleton using the patterns real SDKs need: a
pure-C public header, Pimpl-hidden implementation classes, a pure abstract
backend interface with a single-creation-point factory, a CMake build that
produces a real .framework bundle with an injected Clang module map, and a
build_xcframework.sh that assembles macOS + iOS device + iOS simulator
slices into one .xcframework.
Two --kind profiles are available:
device(default) — discovers/connects to something external and asynchronous (a BLE sensor, a camera, a printer, a medical probe, a network endpoint):Manager→Session→I<Channel>/Simulator<Channel>, withstd::functioncallbacks streamed from a background thread and a simulator backend that fabricates realistic hardware failures (disconnects, jitter, battery drain) for UI development before real hardware exists.library— a self-contained synchronous compute object, no device or connection at all (a codec, an image/signal-processing pipeline, a parser, on-device ML inference): a single Pimpl<Entity>with aCreate → Process → DestroyC API, an explicit-ownership output buffer, and an optional progress callback.
npx skills add logdok/cpp-xcframework-sdkOr manually, for Claude Code:
git clone https://github.com/logdok/cpp-xcframework-sdk ~/.claude/skills/cpp-xcframework-sdk--kind device:
<repo>/
<SDK>/
include/<SDK>.h C-ABI public header (extern "C", POD only)
src/domain/types.h internal C++ types (STL OK, never exported)
src/transport/I<Channel>.h pure abstract backend interface
src/transport/Simulator<Channel>.* concrete simulator backend
src/transport/<Channel>Factory.* single creation point for backends
src/discovery/<Entity>Manager.* Pimpl root service (discovery)
src/session/<Entity>Session.* Pimpl live-connection object
src/capi/<entity>_c_api.cpp C-ABI facade (POD <-> C++ conversion)
src/version.cpp
framework/module.modulemap hand-maintained Clang module map
tools/smoke_test.cpp CLI sanity check, skipped when cross-compiling
CMakeLists.txt
build_xcframework.sh builds 3 slices, wraps into <SDK>.xcframework
CLAUDE.md build commands + architecture notes for this repo
.gitignore
--kind library — same outer shape, flatter core (no discovery/session/transport):
<repo>/
<SDK>/
include/<SDK>.h Create/Process/Destroy, owned-buffer result, progress callback
src/domain/types.h Options, ResultCode, ProgressCallback
src/backend/I<Channel>.h pure abstract compute-backend interface
src/backend/Reference<Channel>.* correctness-first default implementation
src/backend/<Channel>Factory.* single creation point for backends
src/core/<Entity>.* Pimpl compute object, owns the backend
src/capi/<entity>_c_api.cpp C-ABI facade (buffer ownership transfer)
src/version.cpp
framework/module.modulemap
tools/smoke_test.cpp
CMakeLists.txt
build_xcframework.sh
CLAUDE.md
.gitignore
Every generated skeleton has been independently verified to cmake configure,
build, and pass its smoke test — including the full build_xcframework.sh
pipeline (macOS + iOS device + iOS simulator slices assembled into one
.xcframework).
C++ has no stable ABI across compilers or versions. A public header that
leaks std::string, templates, exceptions, or vtables locks every consumer
to the exact toolchain that built the library. This skill's whole design
exists in service of one constraint: the public surface is pure C
(extern "C", fixed-width types, POD structs, opaque handles, C function
pointers), while everything below that boundary is comfortable, idiomatic
C++ (Pimpl, interfaces, STL, threads). See references/architecture-patterns.md
and references/build-pipeline.md in the skill for the full rationale
behind each pattern, including the non-obvious traps (Clang module maps are
not generated by CMake automatically, struct_size-prefixed structs for
forward-compatible growth, why the destructor of a Pimpl class must be
defined out-of-line, etc).
Once installed, just describe what you're building — a BLE sensor SDK, a
network camera control library, a printer SDK — and Claude Code will
interview you for a few names (SDK name, the entity it connects to, a C API
prefix, an internal namespace), then run the bundled scripts/scaffold.py
to generate and verify the project.
You can also invoke the scaffolder directly:
# device kind (default)
python3 scripts/scaffold.py \
--sdk-name SensorSDK --entity-name Sensor --channel-name Link \
--api-prefix SNS --namespace sns \
--output /path/to/repo
# library kind
python3 scripts/scaffold.py --kind library \
--sdk-name ImageCodecSDK --entity-name Encoder \
--api-prefix ICS --namespace ics \
--output /path/to/repoRun python3 scripts/scaffold.py --help for the full flag list.
MIT — see LICENSE.