The C ABI

The model from any language

Core is a C++ and Python library, and it also exposes a flat C ABI so the document model can be driven from any language with a C foreign-function interface: Rust, Swift, Go, Lua, a game engine's scripting host. The C surface mirrors the C++ API: an opaque document handle, functions to shape and read it, and the native serialization.

#include "kinogaki/C.h"
#include <stdio.h>

kinogaki_document_t* s = kinogaki_document_new();

char final[256];                                                  /* add_element writes back the final path */
kinogaki_document_add_element(s, "/world", "group", final, sizeof final);
kinogaki_document_add_element(s, "/world/mat", "material", final, sizeof final);
float rgb[3] = {0.8f, 0.1f, 0.1f};
kinogaki_element_set_float3(s, "/world/mat", "out", rgb);
kinogaki_document_add_element(s, "/world/ball", "object", final, sizeof final);
kinogaki_element_set_float(s, "/world/ball", "radius", 1.5f);
kinogaki_document_connect(s, "/world/mat.out", "/world/ball.albedo");  /* source output → target input */

size_t n = 0;
char* text = kinogaki_document_save_text(s, &n);  /* → .prisma bytes you own */
fwrite(text, 1, n, stdout);
kinogaki_free_buffer(text);
kinogaki_document_free(s);

Already have a coding agent? Skip the hand-written FFI: pip install kinogaki wraps exactly this surface in a Pythonic API.

The shape of the surface

The naming is uniform (kinogaki_<noun>_<verb>) and the lifecycle is explicit:

Ownership rules

The contract is the usual C one, kept deliberately small: the library owns nothing you pass in (strings are copied at the boundary), and you own every buffer the library returns. Release a buffer with kinogaki_free_buffer, and release handles with their _free. Errors are reported through return codes and an out-parameter message rather than exceptions, because exceptions do not cross a C boundary.

Why it's there

The C ABI makes Core reachable from any language. The same document a C++ tool builds, the Server edits, and a human writes by hand can also be created and read from a Python notebook or a Rust service through this surface, with the same paths, the same typed values, the same files. Bind it once for your language and the entire document model is available, with C++ kept out of your call sites.