clawdforge/clients/cpp
Kayos bae34a7701 clients/cpp: initial C++ SDK for clawdforge
Modern C++20 SDK targeting CMake 3.20+. Library is RAII / move-only,
backed by a libcurl easy handle per Client. Public surface is throwing;
exception hierarchy under clawdforge::Error covers AuthError, APIError
(carries status_code + body), TransportError, and ProtocolError.

Dependencies: libcurl + nlohmann/json (FetchContent or find_package).
Tests use cpp-httplib's in-process server + doctest. 12 test cases /
70 assertions cover healthz, run with JSON / text / 502 / files,
multipart upload, full token CRUD, transport failure, URL normalization,
and bad-input rejection. Clean under -Wall -Wextra -Wpedantic -Werror,
ASan + UBSan clean (no leaks, no UB).

upload_file streams via curl_mime_filedata — no in-memory buffering.

Install path produces clawdforge::clawdforge target consumable via
target_link_libraries; FetchContent path mirrors the existing Rust /
Go SDK ergonomics. MIT licensed.
2026-04-28 23:02:51 -07:00
..
cmake clients/cpp: initial C++ SDK for clawdforge 2026-04-28 23:02:51 -07:00
examples clients/cpp: initial C++ SDK for clawdforge 2026-04-28 23:02:51 -07:00
include/clawdforge clients/cpp: initial C++ SDK for clawdforge 2026-04-28 23:02:51 -07:00
src clients/cpp: initial C++ SDK for clawdforge 2026-04-28 23:02:51 -07:00
tests clients/cpp: initial C++ SDK for clawdforge 2026-04-28 23:02:51 -07:00
.gitignore clients/cpp: initial C++ SDK for clawdforge 2026-04-28 23:02:51 -07:00
CMakeLists.txt clients/cpp: initial C++ SDK for clawdforge 2026-04-28 23:02:51 -07:00
README.md clients/cpp: initial C++ SDK for clawdforge 2026-04-28 23:02:51 -07:00

clawdforge — C++ SDK

Modern C++ client for the clawdforge HTTP API. Wraps claude -p subprocess calls behind a bearer-token-gated REST service.

  • C++17 minimum (C++20 lets you use designated initializers in examples).
  • libcurl + nlohmann/json. No Boost.
  • RAII, move-only Client (one libcurl handle per instance).
  • Throwing API; full exception hierarchy under clawdforge::Error.

Install

Option A — FetchContent (drop-in for existing CMake projects)

include(FetchContent)
FetchContent_Declare(clawdforge
    GIT_REPOSITORY https://github.com/Sulkta-Coop/clawdforge.git
    GIT_TAG        main
    SOURCE_SUBDIR  clients/cpp
)
FetchContent_MakeAvailable(clawdforge)

target_link_libraries(my_app PRIVATE clawdforge::clawdforge)

CURL must be available via find_package(CURL REQUIRED). On Debian/Ubuntu: sudo apt install libcurl4-openssl-dev.

Option B — install + find_package

git clone https://github.com/Sulkta-Coop/clawdforge.git
cd clawdforge/clients/cpp
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
sudo cmake --install build

Then in your project:

find_package(clawdforge CONFIG REQUIRED)
target_link_libraries(my_app PRIVATE clawdforge::clawdforge)

Quickstart

#include <clawdforge/client.hpp>
#include <iostream>

namespace cf = clawdforge;

int main() {
    cf::Client client{cf::ClientOptions{
        .base_url = "http://localhost:8800",
        .token    = "cf_...",
    }};

    auto h = client.healthz();
    std::cout << "claude_version=" << h.claude_version << "\n";

    auto r = client.run(cf::RunRequest{
        .prompt = R"(Reply with JSON: {"hello":"world"})",
        .model  = "sonnet",
        .timeout_secs = 60,
    });

    if (auto* j = std::get_if<nlohmann::json>(&r.result)) {
        std::cout << j->at("hello").get<std::string>() << "\n";
    } else if (auto* s = std::get_if<std::string>(&r.result)) {
        std::cout << *s << "\n";
    }
}

API

clawdforge::Client (in <clawdforge/client.hpp>):

Method HTTP Returns
healthz() GET /healthz HealthzResponse
run(req) POST /run RunResult
upload_file(path, ttl_secs=0) POST /files FileToken
create_token(req) POST /admin/tokens AppToken
list_tokens() GET /admin/tokens std::vector<AppTokenInfo>
revoke_token(name) DELETE /admin/tokens/<name> void

All methods throw on failure. ClientOptions lets you set base_url, token, admin_token, timeout, connect_timeout, user_agent, and insecure_tls.

Errors

clawdforge::Error                  // abstract base, derives from std::runtime_error
├── clawdforge::AuthError          // 401 / 403, or missing token on the client
├── clawdforge::APIError           // any other non-2xx — has status_code() + body()
├── clawdforge::TransportError     // libcurl-level failures
└── clawdforge::ProtocolError      // bad URL, missing fields, malformed JSON

Catch broadly:

try {
    client.run(req);
} catch (const cf::AuthError& e) { /* refresh / abort */ }
  catch (const cf::APIError& e)  { std::cerr << e.status_code() << " " << e.body(); }
  catch (const cf::TransportError& e) { /* retry */ }
  catch (const cf::Error& e) { /* anything else */ }

POST /run returns HTTP 502 on subprocess failure. Surfaced as APIError with status_code() == 502; body() parses as the documented RunFailure shape.

File uploads

auto ft  = client.upload_file("/path/to/recipe.png", /*ttl_secs=*/3600);
auto res = client.run(cf::RunRequest{
    .prompt = "extract recipe data",
    .files  = {ft.file_token},
});

The file is streamed off disk via libcurl's curl_mime_filedata — no in-memory buffering of the payload.

Threading

Client is move-only and not thread-safe. Construct one per worker thread or wrap external accesses in a mutex. Multiple Client instances share the process-wide libcurl global state safely (refcounted internally).

Build options

Option Default Effect
CLAWDFORGE_BUILD_TESTS ON (top-level), OFF (subdirectory) doctest-based suite
CLAWDFORGE_BUILD_EXAMPLES ON (top-level), OFF (subdirectory) builds clawdforge_basic_example
CLAWDFORGE_WARNINGS_AS_ERRORS ON -Werror / /WX on the library target

Development

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
ctest --test-dir build --output-on-failure

The test suite spins up a cpp-httplib mock server in-process — no real clawdforge needed.

License

MIT. See LICENSE at the repo root.