Skip to content
Development
Agent

cpp-binding-rules

<!-- GENERATED from docs/api/cpp-binding-rules.md by scripts/build-agent-skill.mjs. Do not edit. -->

BOOST
From plugin
crossbind
14832 skills32 agents
Install
$ npx -y skills add crossbind/crossbind --agent claude-code

How it fires

How this agent gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.

Context preview

The summary Claude sees to decide when to auto-load this agent.

<!-- GENERATED from docs/api/cpp-binding-rules.md by scripts/build-agent-skill.mjs. Do not edit. -->

Agent definition

cpp-binding-rules.md

<!-- GENERATED from docs/api/cpp-binding-rules.md by scripts/build-agent-skill.mjs. Do not edit. -->

C++ Binding Rules — write C++ that crossbind can auto-bind

> crossbind generates JS bindings automatically. There are no `EMSCRIPTEN_BINDINGS` macros to hand-write. But the generator only handles a constrained subset of C++. Stay inside that subset and you get binding-for-free; step outside and you'll need a wrapper or a SWIG escape (`swig-escape.md`).

This doc tells you the rules. **For the canonical type table** (which JS type maps to which C++ type, with `toArray`/`toVector` examples), use the website:

  • `https://crossbind.dev/docs/api/cpp-bindings/overview`
  • `https://crossbind.dev/docs/api/cpp-bindings/data-types`

This page covers what the website doesn't: the **rules** an agent must follow when writing C++ that crossbind will bind.

The hard rules

1. Pointers cross as handles, `const char *` as strings

Raw pointers bind. What the generator cannot turn into an object crosses as a `NativePointer` handle: an opaque JS object that carries the address and owns whatever crossbind allocated for it.

| C++ | JS | |---|---| | `const char *` parameter | `string`, a handle, or `null` | | `const char *` return or callback argument without a following integer | `string` or `null` | | `const char *` callback argument immediately followed by an integer | handle or `null`; read with `readBuffer(pointer, length)` | | `char *`, `unsigned char *`, `void *`, `T **`, pointers to numbers, enums or types the bridge does not know | handle | | `T *` returning a class the bridge knows | instance | | `T *` parameter of a struct the imported header defines, `extern "C"` or not | instance | | `T *` parameter of a struct the bridge only sees declared (`sqlite3`, `PJ`) | handle | | `T *` field of a struct | reads as an instance when `T` is a struct the same header binds, otherwise as a handle; takes either, or `null` | | `int &`, `double &`, `std::string &` out-parameters | handle from `allocPointer` / `allocString`, read back afterwards | | function pointer parameter or field | a JS function, a handle another binding returned, or `null`; a field reads as a handle | | other pointer argument inside a callback | always a handle |

Every module that binds a pointer also exports the helpers: `cstring(text)` and `readCString(handle)`, `allocBuffer(bytes)`, `allocPointer(count)` (both zero-filled), `allocString(text)` and `readString(handle)`, `readNumberAt(handle, index, kind)` / `writeNumberAt(handle, index, kind, value)` with kinds `int8` … `uint64`, `float32`, `float64`, `readPointerAt` / `writePointerAt`, `readBytes(handle, length)` / `writeBytes(handle, u16string)` with one byte per character, `readBuffer(handle, length)` returning a `Uint8Array` copy / `writeBuffer(handle, bytes)` copying any `ArrayBuffer` or view of one (a `Uint8Array`, a Node `Buffer`), and `releaseCallback(fn)` to free a callback slot.

void process(int* data, size_t len);            // handle in, e.g. from allocBuffer
char* getName();                                // handle out: read it, then free it the library's way
int parse(const char* text);                    // takes a JS string
size_t encode(unsigned char* out, size_t cap);  // bytes out through a buffer
const data = allocBuffer(3 * 4);
[7, 8, 9].forEach((n, i) => writeNumberAt(data, i, 'int32', n));
process(data, 3);
const name = readCString(getName());
parse('x=1');
const out = allocBuffer(1024);
const bytes = readBuffer(out, encode(out, 1024)); // Uint8Array

Only the const form converts: C APIs copy a `const char *` input, while a `char *` result is memory the library handed over, so it stays a handle you read and free explicitly. On worker-backed browser builds handles and instances are proxies, `instanceof NativePointer` holds only on direct runtimes, and JS functions cannot cross into a worker.

A string passed for a `const char *` is a copy that lives for the call. When C keeps the pointer afterwards (`sqlite3_bind_text` with `SQLITE_STATIC`), pass a `cstring` handle and keep it until C is done with it, or let C take its own copy (`SQLITE_TRANSIENT`).

A callback's `const char *` followed by an integer may describe bytes with embedded NULs or no terminator. It stays a handle, so Expat's character-data handler can read exactly `readBuffer(text, length)`. If that integer is a status rather than a length and the library guarantees a terminated string, use `readCString(text)`. Read the data while the callback runs; the handle does not keep the library's buffer alive.

Integer and enum parameters take numbers. An enum parameter also takes a member (`await Mode.Fast`), an integer parameter takes an enum member as its value, and a `char` parameter takes a one-character string as its code; anything else throws a `TypeError` instead of crossing as 0. A 64-bit integer (`int64_t`, `long long`, and on React Native also `long` and `size_t`) crosses as a BigInt and takes a BigInt or a safe-integer Number; on wasm32 `long` and `size_t` are 32-bit Numbers.

2. C++11 minimum, C++17 recommended

Build defaults assume modern C++. Use:

  • `std::string`, `std::vector<T>`, `std::map<K,V>`, `std::unordered_map<K,V>`
  • `std::shared_ptr<T>` for heap-allocated objects you return to JS
  • `std::optional<T>` (C++17), `std::variant<...>` (C++17) — supported via website type table
  • Range-based for, `auto`, lambdas, `nullptr`

Runtime notes from the cross-runtime conformance suite: a vector PARAMETER takes a vector instance, which `Module.toVector` builds. A wasm build also takes a plain JS array: for every vector parameter in worker mode, and for a module function's or constructor's in direct mode. By-value `std::vector` RETURNS are real vector proxies on direct runtimes (wasm and jsi), freed like any value JS owns (`lifecycle-and-types.md`), and arrive as plain JS arrays on worker-backed runtimes - that array conversion is the worker contract (`Module.toArray` a

Read more
Ships withcrossbind

Import C++ and Rust like JavaScript modules (WebAssembly & React Native)

Get the whole plugin

Other agents on crossbind.