Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,7 @@ tokio-test = "0.4"
anyhow = "1"
schemars = "0.8"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

[workspace]
members = [".", "contextvm-ffi"]
resolver = "2"
3 changes: 3 additions & 0 deletions contextvm-ffi/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/target
__pycache__/
*.py[cod]
20 changes: 20 additions & 0 deletions contextvm-ffi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "contextvm-ffi"
version = "0.1.0"
edition = "2021"
description = "FFI bindings for the ContextVM SDK — C header + Python/Swift/Kotlin support"
license = "MIT"

[lib]
name = "contextvm_ffi"
crate-type = ["cdylib", "staticlib", "lib"]

[dependencies]
contextvm-sdk = { path = ".." }
nostr-sdk = { version = "0.43", features = ["nip59"] }
tokio = { version = "1", features = ["full"] }
serde_json = "1"
uniffi = "0.29"

[features]
default = []
88 changes: 88 additions & 0 deletions contextvm-ffi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# contextvm-ffi

FFI bindings for the ContextVM Rust SDK.

This crate exposes two binding surfaces:

- A flat C ABI in `headers/contextvm.h`
- UniFFI objects for Python, Kotlin, and Swift

Async SDK operations are driven by an internal Tokio runtime, so foreign callers
use blocking functions and do not need to manage Rust async state.

## Build

```bash
cd contextvm-ffi
cargo build --release
```

Outputs:

- Linux: `target/release/libcontextvm_ffi.so`
- macOS: `target/release/libcontextvm_ffi.dylib`
- Windows: `target/release/contextvm_ffi.dll`

## Generate UniFFI Bindings

Build the shared library first, then generate bindings from the compiled
library metadata using `uniffi-bindgen` 0.29.x:

```bash
cd contextvm-ffi
cargo build

uniffi-bindgen generate target/debug/libcontextvm_ffi.so \
--library \
--crate contextvm_ffi \
--language python \
--out-dir python/
```

Use `--language kotlin` or `--language swift` for the other supported targets.

## C API

Include `headers/contextvm.h` and link against `libcontextvm_ffi`.

```c
#include "contextvm.h"

CvmError *error = NULL;
CvmHandle keys = cvm_keys_generate(&error);

char *public_key = cvm_keys_public_key(keys, &error);
cvm_string_free(public_key);

cvm_keys_free(keys);
```

Errors are opaque. Use `cvm_error_code`, `cvm_error_message`, and
`cvm_error_free` to inspect and release them.

Mode fields in `CvmServerConfig` and `CvmClientConfig` are raw `int32_t`
values. Set them with the `CVM_ENCRYPTION_*` and `CVM_GIFTWRAP_*` constants;
invalid values are rejected with `CVM_VALIDATION`.

## JSON Arguments

Several parity APIs use JSON strings to represent SDK values that are not
portable C structs:

- `profile_metadata_json`: a `ProfileMetadata` JSON object.
- `*_publish_tools/resources/prompts/resource_templates`: a JSON array of MCP
capability objects.
- `*_set_announcement_*_tags`: a JSON array of Nostr tag arrays, for example
`[["pricing","free"]]`.

## Memory Management

Rust-owned values returned through the C ABI must be released by the caller:

- Strings: `cvm_string_free`
- Messages: `cvm_message_free`
- Incoming requests: `cvm_incoming_request_free`
- Announcement arrays: `cvm_announcements_free`
- Discovered tool arrays: `cvm_discovered_tools_free`
- Provider profile arrays: `cvm_provider_profiles_free`
- Errors: `cvm_error_free`
Loading
Loading