Getting started #
Requirements #
- A C23 compiler (Clang ships with Xcode Command Line Tools on macOS)
- CMake ≥ 3.20
- libcurl
- OpenSSL (libcrypto) — for SHA-256 hashing
- libsecp256k1 — for secp256k1 signing (optional; crypto stubs gracefully if absent)
- c-ares 1.28+ — for portable DNS TXT resolution (optional; POSIX resolver fallback)
- libzstd — for Jetstream compressed messages (optional)
- SQLite3 — only required when building the optional persistence module
(
WOLFRAM_BUILD_STORE=ON); the default build does not link it - libsodium — only required when
WOLFRAM_BUILD_STORE_CRYPTO=ON(which also requiresWOLFRAM_BUILD_STORE=ON); it provides secret-key encryption (crypto_secretbox_easy, XSalsa20-Poly1305) and passphrase key derivation (crypto_pwhash, Argon2id) for persisted sessions at rest - libmicrohttpd (GNU MHD) — only required when
WOLFRAM_BUILD_TEST_HTTPD=ONfor the offline HTTP integration test (mock_pds) - libidn2 (GNU, MIT) — only required when
WOLFRAM_BUILD_IDN=ON. It provides IDNA2008 / punycode (ACE,xn--…) conversion for internationalized handles
On macOS via Homebrew:
brew install cmake curl openssl secp256k1 c-ares zstd
# Optional persistence + at-rest encryption:
brew install sqlite3 libsodium
# Optional offline HTTP integration test (WOLFRAM_BUILD_TEST_HTTPD=ON):
brew install libmicrohttpd
# Optional internationalized (IDN) handle resolution (WOLFRAM_BUILD_IDN=ON):
brew install libidn2
(libcurl also ships with macOS itself, but the Homebrew one is newer and CMake
finds it more reliably via pkg-config.) Jetstream connections require libcurl
7.86+ built with ws/wss support; without it, WebSocket attempts return
WF_ERR_INVALID_ARG. Compressed Jetstream subscriptions additionally require
libzstd and the official Jetstream dictionary,
supplied through wf_jetstream_options.
Building #
cmake -S . -B build
cmake --build build
ctest --test-dir build
The generated Lexicon wrappers (include/wolfram/atproto_lex.h and
src/atproto_lex.c) are prebuilt and checked into the repository, so a fresh
clone compiles without running wf_lexgen.cpp. You only need it to regenerate
wrappers from a different/newest Lexicon set or a custom lexicon.
If Homebrew's libcurl isn't picked up automatically:
cmake -S . -B build -DCMAKE_PREFIX_PATH="$(brew --prefix curl)"
Optional persistence and at-rest encryption #
# Persistence only (sessions + repo mirror stored in plaintext columns):
cmake -S . -B build -DWOLFRAM_BUILD_STORE=ON
# Persistence with libsodium at-rest encryption of the session blob:
cmake -S . -B build -DWOLFRAM_BUILD_STORE=ON -DWOLFRAM_BUILD_STORE_CRYPTO=ON
With WOLFRAM_BUILD_STORE_CRYPTO=ON, call wf_store_set_passphrase after
wf_store_open and before saving/loading a session; the key is derived via
libsodium's crypto_pwhash (Argon2id).
Generating Lexicon wrappers #
cmake --build build --target wf_lexgen_tool
./build/wf_lexgen_tool path/to/lexicons/*.json -o generated/lexicons.h
# Add generated JSON codecs and XRPC wrappers:
./build/wf_lexgen_tool path/to/lexicons/*.json -o generated/lexicons.h \
--source-output generated/lexicons.c
Generated structs cover records, named object definitions, and XRPC parameters,
inputs, and outputs. Optional fields have explicit has_* flags; inputs are
borrowed and must outlive the struct, while output decoders return owning
objects with a _output_free. Input encoders resolve referenced objects,
arrays, strings, and tokens recursively.
The CLI #
The default build produces ./build/wolfram, the primary command-line client:
./build/wolfram post https://bsky.social you@example.com yourpassword "Hello!"
./build/wolfram help # every command
./build/wolfram help post # one command
docs/cli.md documents it in full.
Examples #
The programs below are separate single-purpose binaries under examples/,
built only when configured with -DWOLFRAM_BUILD_EXAMPLES=ON. They are not
produced by the default build:
./build/describe_repo https://eurosky.social did:plc:ofrbh253gwicbkc5nktqepol
./build/create_post https://bsky.social you@example.com yourpassword "Hello from wolfram!"
./build/upload_image https://bsky.social you@example.com yourpassword ./cat.jpg "a cat"
./build/get_record https://bsky.social did:plc:example app.bsky.feed.post 3jui7kd54zh2y
./build/subscribe_labels https://mod.bsky.app
./build/create_account https://bsky.social alice.bsky.social alice@example.com hunter2
./build/create_app_password https://bsky.social alice@example.com hunter2 "my-app"
End-to-end examples also live in examples/: feed_generator,
labeler_service, ozone_moderation, post_image_embed, and
timeline_moderation.
Available modules and guides #
wolfram's features are split across focused modules, each with a usage guide:
- Agent / high-level API — agent.md, typed_api.md (feed, thread, graph, list, embed, notification, and the new unspecced.md typed parsers)
- Identity & server management — DID/handle resolution plus
com.atproto.identityaccount ops andcom.atproto.serveraccount lifecycle. See identity.md. - Moderation & labeling — moderation.md
- Sync / repo mirror — sync.md
- Video upload — upload a video blob, poll the job status, and embed it in a post. See video.md.
- OAuth / DPoP — oauth.md
- Validation — validate.md; Notifications — notification.md; Agent internals — agent_usage.md
Build everything with the commands in Building above, then pick the guide that matches what you're building.