This is a Pony project. The ponylang org maintains a set of LLM coding skills. Get set up with them before contributing:
-
Not set up yet? Install them once:
git clone https://github.com/ponylang/llm-skills.git cd llm-skills python install.py -
Already set up? Make sure you're on the latest. If you installed with the script above,
git pullin the directory where you clonedllm-skillsand the symlinked skills update automatically — if you set them up another way, refresh them however that setup expects.
See the llm-skills README for details and other harnesses.
When you start working on this project, load the pony-skills skill — it tells your assistant which Pony skill to use for each task.
Read CONTRIBUTING.md.
The build uses CMake presets (see BUILD.md). The self-hosted tools' test binaries — for the compiler, pony-lsp, pony-lint, pony-doc, and pony-dep — are built on demand: a normal cmake --build does not build them. Build the test target, then run it through ctest:
cmake --build --preset debug --target pony-compiler-tests && ctest --preset debug -R pony-compiler-testscmake --build --preset debug --target pony-lsp-tests && ctest --preset debug -R pony-lsp-testscmake --build --preset debug --target pony-lint-tests && ctest --preset debug -R pony-lint-testscmake --build --preset debug --target pony-doc-tests && ctest --preset debug -R pony-doc-testscmake --build --preset debug --target pony-dep-tests && ctest --preset debug -R pony-dep-tests
The first build of a test binary compiles from Pony source (~60s); later runs skip the rebuild when nothing under its source tree changed. On Windows, use the windows-x86-64-debug preset the same way.
To lint a tool's own source, run the pony-lint binary (built by a normal cmake --build --preset debug) against the tool's directory:
cd build/debug && PONYPATH=../../tools/lib/ponylang/pony_compiler ./pony-lint ../../tools/pony-lint/
The same works for ../../tools/pony-lsp/, ../../tools/pony-doc/, and ../../tools/pony-dep/.
Never add a mutex or a new thread unless the idea came from the human operator or a committer expressly approved it. Pony's runtime is built on a deliberate concurrency model, and adding either is an architectural decision, not an implementation detail. If a change looks like it needs one, stop and raise it rather than writing it.
On the Windows MSVC build, libponyrt's .c files compile as C++ (src/libponyrt/CMakeLists.txt sets LANGUAGE CXX on them). A PONY_API function whose definition is not inside a PONY_EXTERN_C_BEGIN/PONY_EXTERN_C_END region gets a C++-mangled symbol, which the stdlib FFI — referencing the plain C name — can't resolve at link (lld-link: undefined symbol). Linux, macOS, and BSD compile .c as C, so the failure is Windows-only and won't show up in a local build there. Every runtime .c already wraps its definitions in that region (see lang/stat.c, lang/socket.c); put any new PONY_API function inside it. To check a symbol's linkage, run dumpbin /SYMBOLS <lib> | findstr <name> from a vcvars64 shell: a C-linkage function shows the plain name, a mangled one shows the C++ form.
gh workflow run <workflow> --ref <branch> -f ref=<branch> — both flags are needed. --ref selects which branch the workflow YAML is read from; -f ref= sets the inputs.ref that the checkout step uses. Without -f ref=, the job checks out main regardless of --ref.
Load the /pony-release-notes skill for the full procedure. The one thing to know without it: add a .release-notes/<slug>.md file for each user-facing PR — do not edit next-release.md directly, because CI aggregates the individual files.