Native Library (C FFI)
The kairos-ffi crate exports a C-compatible shared library with an auto-generated header (kairos_engine.h). It provides three handle types for different integration patterns.
# Core engine onlycargo build -p kairos-ffi --profile release-native
# With fly-by-wire session supportcargo build -p kairos-ffi --profile release-native --features fly-by-wire
# With research-mode substrate constructorscargo build -p kairos-ffi --profile release-native --features fly-by-wire,dynamic-configOutputs:
- Linux:
libkairos_engine.so - macOS:
libkairos_engine.dylib - Windows:
kairos_engine.dll - Static:
libkairos_engine.a - Header:
kairos_engine.h(auto-generated bycbindgen)
Handle Types
Section titled “Handle Types”| Handle | Purpose | Feature flag |
|---|---|---|
KairosEngine | Raw simulation — standalone tick execution | Always available |
KairosSubstrate | Stateless policy evaluation (no engine) | fly-by-wire |
KairosSession | Combined runtime + engine control loop | fly-by-wire |
Memory Rules
Section titled “Memory Rules”- Every non-NULL
char*return must be freed withkairos_string_free() - Handle pointers must be freed with their respective
_destroy()or_free()functions - Passing NULL to any free function is safe (no-op)
- All Rust panics are caught at FFI boundaries — no undefined behavior crosses the boundary
// Correct usagechar *state = kairos_engine_get_state(engine);// ... use state ...kairos_string_free(state);
// Correct cleanupkairos_engine_destroy(engine); // NULL-safeError Handling
Section titled “Error Handling”- Functions returning
char*: returnNULLon error - Functions returning
int32_t: return0on success,-1on error - After any error, call
kairos_last_error()for a JSON error message kairos_last_error()is thread-local — safe to call from multiple threads
char *result = kairos_engine_run_tick(engine, "left");if (!result) { const char *err = kairos_last_error(); fprintf(stderr, "Error: %s\n", err); // err is static thread-local — do not free}kairos_string_free(result);Engine API
Section titled “Engine API”Lifecycle
Section titled “Lifecycle”KairosEngine *kairos_engine_create(const char *config_json);void kairos_engine_destroy(KairosEngine *engine);int32_t kairos_engine_reset(KairosEngine *engine);Config JSON:
{ "columns": 25, "rows": 17, "lambda": 0.65, "gamma": 0.1, "enableGhostTraces": true}Configuration
Section titled “Configuration”void kairos_engine_set_seed(KairosEngine *engine, uint32_t seed);void kairos_engine_set_lambda(KairosEngine *engine, double lambda);void kairos_engine_set_gamma(KairosEngine *engine, double gamma);int32_t kairos_engine_load_scenario(KairosEngine *engine, const char *scenario_json);int32_t kairos_engine_load_event_script(KairosEngine *engine, const char *events_json);int32_t kairos_engine_add_agent(KairosEngine *engine, const char *agent_json);Tick Execution
Section titled “Tick Execution”char *kairos_engine_run_tick(KairosEngine *engine, const char *move_direction);char *kairos_engine_run_tick_multi(KairosEngine *engine, const char *moves_json);char *kairos_engine_decide_next_move(const KairosEngine *engine);char *kairos_engine_decide_all_moves(const KairosEngine *engine);decide_next_move returns plain text ("left", "stay", "right") — not JSON. All other functions return JSON strings.
State Access
Section titled “State Access”char *kairos_engine_get_state(const KairosEngine *engine);char *kairos_engine_get_warning(const KairosEngine *engine);char *kairos_engine_get_reachability_map(const KairosEngine *engine);char *kairos_engine_get_agent_states(const KairosEngine *engine);Trace Recording
Section titled “Trace Recording”void kairos_engine_start_recording(KairosEngine *engine, const char *scenario_id);char *kairos_engine_stop_recording(KairosEngine *engine);Substrate API
Section titled “Substrate API”Stateless policy evaluation without an engine. Evaluates a single request against the calibration artifact and deployment policy.
KairosSubstrate *kairos_substrate_new( const char *policy_path, const char *license_path, const uint8_t *hmac_secret, uintptr_t hmac_secret_len);
char *kairos_substrate_evaluate( const KairosSubstrate *substrate, const char *request_json);
void kairos_substrate_free(KairosSubstrate *substrate);With dynamic-config feature (research mode):
KairosSubstrate *kairos_substrate_new_research( const char *config_path, const char *policy_path, const char *license_path, const uint8_t *hmac_secret, uintptr_t hmac_secret_len);KairosSubstrate is immutable after construction — safe for concurrent reads from multiple threads.
Session API
Section titled “Session API”Requires fly-by-wire feature. Combines the runtime and engine into a stateful control loop.
Lifecycle
Section titled “Lifecycle”KairosSession *kairos_session_new( const char *engine_config_json, const char *policy_path, const char *license_path, const uint8_t *hmac_secret, uintptr_t hmac_secret_len);
void kairos_session_free(KairosSession *session);Evaluation & Stepping
Section titled “Evaluation & Stepping”// Evaluate without advancing timechar *kairos_session_evaluate( const KairosSession *session, const char *request_json);
// Advance engine timechar *kairos_session_step( const KairosSession *session, const char *move_direction);char *kairos_session_step_actor( const KairosSession *session, const char *actor_id, const char *move_direction);char *kairos_session_step_multi( const KairosSession *session, const char *moves_json);Telemetry
Section titled “Telemetry”char *kairos_session_get_telemetry(const KairosSession *session);char *kairos_session_get_telemetry_for_actor( const KairosSession *session, const char *actor_id);Scenario Management
Section titled “Scenario Management”int32_t kairos_session_load_scenario( const KairosSession *session, const char *scenario_json);Complete Example
Section titled “Complete Example”#include "kairos_engine.h"#include <stdio.h>
int main() { KairosEngine *engine = kairos_engine_create( "{\"columns\":25,\"rows\":17,\"lambda\":0.65,\"gamma\":0.1}" ); if (!engine) { fprintf(stderr, "Error: %s\n", kairos_last_error()); return 1; }
kairos_engine_set_seed(engine, 1207);
for (int i = 0; i < 200; i++) { char *move = kairos_engine_decide_next_move(engine); char *result = kairos_engine_run_tick(engine, move); kairos_string_free(move); kairos_string_free(result); }
kairos_engine_destroy(engine); return 0;}Thread Safety
Section titled “Thread Safety”- Each handle instance is not thread-safe — do not share across threads without synchronization
KairosSubstrateis immutable after construction — concurrent reads are safekairos_last_error()is thread-local — does not interfere across threads- Multiple independent handles on separate threads are supported
Data Exchange
Section titled “Data Exchange”All complex data crosses the FFI boundary as JSON strings. The caller is responsible for parsing JSON responses and freeing returned strings with kairos_string_free().