This page is for contributors changing icey itself.
The architecture and module guides explain how the runtime works. The contributing guide explains workflow and release mechanics. This page covers the repository-specific rules that keep new code aligned with the existing structure.
Each module lives under src/<module>/.
The normal layout is:
src/<module>/
├── CMakeLists.txt
├── README.md
├── include/icy/... # public headers
├── src/ # implementation
├── tests/ # behavioural and contract coverage
├── samples/ # runnable examples
├── bench/ # focused microbenchmarks
├── perf/ # comparative or reportable performance harnesses
├── fuzz/ # fuzz targets for parser or protocol surfaces
└── apps/ # product-style binaries layered on the moduleOnly the first four are expected everywhere. The rest are added when the module actually needs them.
Use the module README as the short local map: namespace, CMake target, primary headers, directory layout, and the next docs to read. Keep that README brief and contributor-oriented.
src/<module>/include/icy/....src/<module>/src/.icey::<module> namespace.icey.Do not add new public headers outside include/icy. If a type is part of the supported API surface, it should be discoverable there.
New modules should follow the existing target pattern and be declared with icy_add_module(...).
The expectations are:
DEPENDSPACKAGESHAVE_OPENSSL, HAVE_FFMPEG, or HAVE_LIBDATACHANNELPUBLIC only when the public headers require themPRIVATEThe repo is intentionally target-based. Avoid ad-hoc global include paths, raw compiler flag mutation, or implicit transitive dependency assumptions when a target declaration can state the contract directly.
Most behavioural bugs in icey come from violating the runtime model, not from syntax or formatting drift.
Before changing base, net, http, av, or webrtc, keep these rules in view:
send() is the borrowed fast path and sendOwned() is the retained pathPacketStream stays zero-copy until an explicit retention boundaryclose() is asynchronousUse runtime-contracts.md as the source of truth. Do not widen contracts "just in case" by making a signal cross-thread, adding retention, or inserting queues unless the code path actually needs that broader contract.
tests/ directory or the top-level tests/ tree.Tests are not an afterthought here. If a change touches lifetime, shutdown, ownership, protocol parsing, queueing, or async state flow, assume it needs a test unless there is a clear reason it does not.
When the public surface changes, update the docs that own that surface.
That usually means some combination of:
docs/modules/docs/concepts/docs/recipes/src/<module>/README.mdREADME.md, CHANGELOG.md, or release notes when the change is externally visibleKeep generated API reference concerns separate from prose docs. The prose explains the model and workflows; the generated API tab explains the exact types and signatures.
The repo has already been renamed to icey. Do not introduce new references to the older LibSourcey, Sourcey, or scy project naming for library code, namespaces, include paths, or contributor docs unless you are referring to an external tool or historical changelog entry on purpose.