C++ SDK

Header-only C++17 RAII wrapper over libreflow_rt_capi. Lives at sdk/cpp/ in the repo. No package manager today — pull the header directly + link the runtime library.

Requirements

  • C++17 compiler (clang ≥ 9, gcc ≥ 9, MSVC 2019+)
  • libreflow_rt_capi.{so,dylib,dll} — install via either the sdk/go/v* GitHub Release tarballs (pre-built per triple) or by building from the monorepo (cargo build -p reflow_rt_capi --release).

Install

# Drop the header tree under your third_party/.
git clone --branch sdk/go/v0.2.1 --depth 1 \
    https://github.com/offbit-ai/reflow third_party/reflow

# Grab the matching native lib for your platform.
VER=0.2.1
TRIPLE=aarch64-apple-darwin
curl -LO https://github.com/offbit-ai/reflow/releases/download/sdk/go/v$VER/reflow-rt-capi-$TRIPLE-v$VER.tar.gz
sudo tar -xzf reflow-rt-capi-$TRIPLE-v$VER.tar.gz -C /usr/local

CMake:

add_subdirectory(third_party/reflow/sdk/cpp)
target_link_libraries(myapp PRIVATE reflow::cpp)

If find_library(reflow_rt_capi) doesn't pick up the runtime automatically:

set(REFLOW_RT_CAPI_LIB "/usr/local/lib/libreflow_rt_capi.dylib")
add_subdirectory(third_party/reflow/sdk/cpp)

Hello world

#include <reflow/reflow.hpp>
#include <atomic>
#include <chrono>
#include <thread>

int main() {
    reflow::Network net;

    auto doubler = reflow::Actor::from_callback(
        "doubler", {"in"}, {"out"},
        [](reflow::Context& ctx) {
            auto in = ctx.input_json("in");
            if (!in) return;
            auto pos = in->find("\"data\":");
            if (pos == std::string::npos) return;
            int64_t n = std::stoll(in->substr(pos + 7));
            ctx.emit("out", reflow::Message::integer(n * 2));
        });

    std::atomic<int64_t> got{0};
    auto collector = reflow::Actor::from_callback(
        "collector", {"in"}, {},
        [&](reflow::Context& ctx) {
            if (auto m = ctx.take_input("in")) {
                auto j = m->as_json();
                auto pos = j.find("\"data\":");
                if (pos != std::string::npos) got = std::stoll(j.substr(pos + 7));
            }
        });

    net.register_actor("tpl_doubler", std::move(doubler));
    net.register_actor("tpl_collector", std::move(collector));
    net.add_node("a", "tpl_doubler");
    net.add_node("b", "tpl_collector");
    net.add_connection("a", "out", "b", "in");
    net.add_initial("a", "in", R"({"type":"Integer","data":21})");
    net.start();

    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    std::cout << "got: " << got.load() << "\n";  // → 42
    net.shutdown();
}

Authoring graphs

reflow::Graph g("demo");
g.add_node("a", "tpl_x");
g.add_node("b", "tpl_y");
g.add_connection("a", "out", "b", "in");
g.add_group("pipe", R"(["a","b"])", R"({"caption":"pipeline"})");
g.rename_node("a", "alpha");

if (auto node = g.get_node_json("alpha")) std::cout << *node << "\n";
std::cout << g.groups_json() << "\n";
std::cout << g.connections_json() << "\n";

std::optional<std::string> for nullable returns (get_node_json, get_connection_json); plain std::string everywhere else. Pick your own JSON parser — nlohmann/json, simdjson, RapidJSON, etc.

Error handling

Every C ABI call is checked. Non-OK status throws reflow::Error, which carries the original rfl_status and the runtime's last error string:

try {
    net.add_initial("missing-actor", "in", R"({"type":"Flow"})");
} catch (const reflow::Error& e) {
    std::cerr << e.what() << " status=" << e.status() << "\n";
}

Packs

auto templates = reflow::pack::load("./reflow.pack.ml-0.2.0.rflpack");
auto manifest  = reflow::pack::inspect_json("./reflow.pack.ml-0.2.0.rflpack");
auto loaded    = reflow::pack::list_json();

See Packs for the full pack workflow.

Subgraphs

reflow::SubgraphBuilder sub(graph_export_json);
sub.register_actor("my_custom", std::move(custom_actor));
sub.fill_from_catalog();
auto sg = sub.build();
net.register_actor("tpl_sub", std::move(sg));

ABI lockstep

The C++ wrapper has no version of its own — it tracks the libreflow_rt_capi it links against. Pull the header from the same tag as the runtime tarball you install. reflow::pack::abi_version() returns the runtime's pack-ABI hash so you can sanity-check at startup.

See also