Epic: CPEX Rust Core (#12)
Summary
Create the C FFI layer (cpex-ffi crate) and Go bindings (go/ package) as the first language binding for the Rust core. Go is prioritized for K8s deployments expressed interest and Python already has a complete implementation.
Motivation
Kagenti and other Go-based agent platforms need CPEX plugin execution with the same semantics as the Python/Rust implementations. A shared Rust core with Go bindings ensures behavioral parity without reimplementing the PluginManager in Go.
Scope
cpex-ffi crate
#[repr(C)] result struct — continue_processing, violation_code, violation_reason, modified_payload (pointer + length)
- Opaque handle types —
cpex_manager_t, managed via Arc internally
- Lifecycle —
cpex_manager_new(), cpex_manager_free()
- Hook dispatch —
cpex_invoke_hook() with payload as byte buffer (MessagePack default, JSON debug)
- Result access —
cpex_result_blocked(), cpex_result_payload(), cpex_result_free()
- Error reporting —
cpex_last_error() (thread-local)
- ABI versioning —
cpex_abi_version()
cbindgen.toml → generates include/cpex.h
Go bindings (go/)
go.mod with module path github.com/contextforge/cpex/go, package name cpex
cpex.go — NewManager(), InvokeHook(), Close()
types.go — PluginResult, HookType, Extensions
errors.go — error types bridging cpex_last_error()
internal/ffi.go — cgo bindings to cpex.h (pkg-config + relative path fallback)
internal/memory.go — handle lifecycle, free safety
Wire Format
- MessagePack as default (fast, compact, schema-less)
- JSON as debug option (human-readable)
- Zero-copy where possible: Go pins memory for input, Rust reads directly. C struct envelope for result scalars.
Acceptance Criteria
go test ./... passes from the monorepo (cargo build -p cpex-ffi && cd go && go test)
cpex.NewManager() initializes a Rust PluginManager via cgo
cpex.InvokeHook() dispatches through the 5-phase executor
- ABI version check at init time
- Result envelope readable without deserialization (C struct scalars)
- Payload serialized only when modified
Epic: CPEX Rust Core (#12)
Summary
Create the C FFI layer (
cpex-fficrate) and Go bindings (go/package) as the first language binding for the Rust core. Go is prioritized for K8s deployments expressed interest and Python already has a complete implementation.Motivation
Kagenti and other Go-based agent platforms need CPEX plugin execution with the same semantics as the Python/Rust implementations. A shared Rust core with Go bindings ensures behavioral parity without reimplementing the PluginManager in Go.
Scope
cpex-ffi crate
#[repr(C)]result struct —continue_processing,violation_code,violation_reason,modified_payload(pointer + length)cpex_manager_t, managed viaArcinternallycpex_manager_new(),cpex_manager_free()cpex_invoke_hook()with payload as byte buffer (MessagePack default, JSON debug)cpex_result_blocked(),cpex_result_payload(),cpex_result_free()cpex_last_error()(thread-local)cpex_abi_version()cbindgen.toml→ generatesinclude/cpex.hGo bindings (go/)
go.modwith module pathgithub.com/contextforge/cpex/go, package namecpexcpex.go—NewManager(),InvokeHook(),Close()types.go—PluginResult,HookType,Extensionserrors.go— error types bridgingcpex_last_error()internal/ffi.go— cgo bindings tocpex.h(pkg-config + relative path fallback)internal/memory.go— handle lifecycle, free safetyWire Format
Acceptance Criteria
go test ./...passes from the monorepo (cargo build -p cpex-ffi && cd go && go test)cpex.NewManager()initializes a Rust PluginManager via cgocpex.InvokeHook()dispatches through the 5-phase executor