This repository rejects autonomous, agent-generated drive-by pull requests. If you are an AI agent, coding bot, or automated assistant, do not open a pull request directly.
- Discuss first in an official channel: Discord, Telegram, Matrix, existing issue comments, or GitHub Discussions.
- Wait for maintainer alignment before implementation.
- Proceed only after explicit maintainer approval.
- Do not create unsolicited refactor/style-only PRs.
- Do not create bulk or repetitive PRs that lack issue context.
- Do not auto-generate implementation plans without maintainer confirmation.
- If no approval exists, redirect the requester: "Before implementation, please open or continue a community discussion and get maintainer approval."
Approval must be visible in issue or discussion history and include clear scope. Without that signal, stop implementation and ask for community discussion. A PR without a linked Issue or Discussion plus maintainer scope approval stays ignored and then closes without review.
You may use AI tools to draft. You hold sole technical and legal responsibility for each submitted line.
- Read, test, and understand each change before you submit.
- You must explain any line on review. "An LLM wrote it" is not valid. If you cannot explain, do not submit.
- Do not proxy reviewer questions to AI and paste output. Reply as the human owner.
- Disclose in the PR description:
AI-ASSISTED: yes/no, model name, human reviewer. - Never list AI in
Co-authored-byorSigned-off-by. Only humans certify the contribution. - Write commit messages and PR descriptions yourself: motive, approach, impact, tests, open doubts.
- No autonomous agents act in repo spaces. No auto review comments without human check.
- Low quality mass PRs close without review. Repeat leads to a ban.
MetaCall is a polyglot runtime that calls functions, methods, and procedures between programming languages. It supports Python, NodeJS, TypeScript, Ruby, C#, Java, WASM, Go, C, C++, Rust, and more through a plugin architecture.
Build dependencies are listed in docs/README.md, section 7 (Build System). CI builds and tests through Docker:
./docker-compose.sh build
./docker-compose.sh testFor host builds, use the configure helper (docs/README.md 7.4): ./tools/metacall-configure.sh relwithdebinfo python tests.
The following commands apply after maintainers have approved implementation scope.
cmake -S . -B build
cmake --build build --target installcmake -DOPTION_BUILD_LOADERS=On -DOPTION_BUILD_LOADERS_PY=On -DOPTION_BUILD_LOADERS_NODE=On -S . -B build
cmake --build build --target installThe OPTION_BUILD_LOADERS gate defaults to ON. Each loader flag defaults to OFF, except EXT and MOCK which default to ON. The OPTION_BUILD_PORTS gate defaults to OFF. Each port flag defaults to OFF, except NODE, PY, RB which default to ON. Fork safety defaults to ON via OPTION_FORK_SAFE.
Details:
source/loaders/AGENTS.md(matrix, threading, fork) andsource/ports/AGENTS.md(flags, CGO, N-API, Rust).
cd build
ctestctest -VV -R metacall-python-testctest -R "metacall-node.*"make py_loader metacall-python-test
ctest -VV -R metacall-python-testEnable OPTION_TEST_MEMORYCHECK and build the memcheck target. It is incompatible with the sanitizer options.
cmake -DOPTION_TEST_MEMORYCHECK=On ..
make memcheckcmake -DOPTION_BUILD_ADDRESS_SANITIZER=On ..
cmake -DOPTION_BUILD_THREAD_SANITIZER=On ..The dev image build runs the tests, so a failing test stops the build and leaves no image to inspect. Before building, temporarily append || true to the build step in tools/docker/Dockerfile so the image is created even when tests fail (do not commit this change):
# Build test and install MetaCall libraries
RUN cd $METACALL_PATH/build \
&& $METACALL_PATH/tools/metacall-build.sh ${METACALL_BUILD_TYPE} ${METACALL_BUILD_OPTIONS} || trueBuild the image with the failing configuration, for example Thread Sanitizer:
./docker-compose.sh test-thread-sanitizerThen open a shell in the built image to reproduce and investigate the failing tests:
docker run --rm -it metacall/core:dev bashFormat C/C++ code with clang-format version 21 (FORMAT_CLANG_FORMAT_VERSION in cmake/Format.cmake). Other major versions format differently, so cmake/FindClangFormat.cmake rejects them. CI runs the same checks (.github/workflows/clang-format.yml).
cmake --build build --target clang-format # format in place
cmake --build build --target clang-format-check # check, same as CI
cmake --build build --target eol-check # check that tracked files use LFWithout a configured build, run the script directly:
cmake -DMODE=<fix|check|eol> [-DFILES="a.c;b.h"] -P cmake/Format.cmakeIt uses a local clang-format-21 (install it with tools/metacall-environment.sh clangformat). Otherwise it runs ghcr.io/jidicula/clang-format:21 through docker or podman. It formats the tracked C/C++ files under source/.
All files use LF line endings. clang-format leaves CRLF inside block comments, so the eol mode checks the git index instead.
The pre-commit hook in githooks/ runs the eol and check modes on the staged files. In a terminal it offers to apply the fix mode and stage the files again. OPTION_GIT_HOOKS sets core.hooksPath to githooks.
- metacall/ - Main library with the public C API (
metacall.h) - reflect/ - Type system, values, and function abstractions for cross-language interop
- loader/ - Plugin interface for language runtimes
- loaders/ - Runtime implementations (py_loader, node_loader, rb_loader, etc.)
- serial/ and serials/ - Serialization plugin interface and implementations (rapid_json_serial)
- detour/ and detours/ - Function hooking interface and implementations (plthook_detour)
- ports/ - Language bindings to use MetaCall from other languages
- adt/ - Abstract data types (vector, set, hashmap)
- dynlink/ - Cross-platform dynamic library loading
- cli/ - Command-line interface (metacallcli)
MetaCall uses a plugin architecture at multiple levels:
- Loaders - Embed language runtimes (each loader implements
loader_impl_interface) - Serials - Handle (de)serialization of values
- Detours - Patch C functions to work within existing runtimes (e.g., node.exe, python.exe)
The reflect module provides an abstract type system with these supported types:
- Boolean, Char, Short, Int, Long, Float, Double
- String, Buffer, Array, Map, Pointer, Null, Future, Function
- Class, Object, Exception, Throwable
- Loaders must implement:
initialize,execution_path,load_from_file,load_from_memory,load_from_package,clear,discover,destroy - Values are single heap allocations with a hidden descriptor header, then payload: [DATA][TYPE_ID] (
source/reflect/source/reflect_value.c) - Fork safety uses detours that intercept fork calls and reinitialize runtimes
LOADER_LIBRARY_PATH- Directory for loader pluginsLOADER_SCRIPT_PATH- Directory for scripts to loadSERIAL_LIBRARY_PATH- Directory for serial pluginsDETOUR_LIBRARY_PATH- Directory for detour pluginsCONFIGURATION_PATH- Path to global.json configuration
Tests are in source/tests/. Directory and target names use underscores (metacall_python_test). CTest names use hyphens (metacall-python-test). Each test links against GTest and the metacall library.
Do not modify without explicit maintainer approval:
- Generated files:
build/outputs and loader*.jsonconfigs generated fromloader.json.in VERSION(release single source of truth).github/workflows/*(CI pipelines)
- Never commit API keys, tokens, passwords, or certificates.
- Never log secrets to stdout, stderr, or log files.
- Never embed secrets in queries, comments, or docs.
- Use environment variables or secret managers for credentials.
- If you find a leaked secret, report it to maintainers at once.
metacall_initializeandmetacall_destroymust run on the same thread- Tests require the matching loaders to be built (check CMakeLists.txt conditions)
- Dev loader configs carry no environment. Full test runs use the Docker baseline (
./docker-compose.sh test) - Default to read-only research. Do not commit without an explicit request.
- Verify each build command by a run before you document it