Contributing
Contributions are welcome: adding a grammar, fixing a bug, improving a binding, or writing documentation.
For CI/CD workflow details, see the CI/CD reference.
Prerequisites
Section titled “Prerequisites”You’ll need the following tools installed:
- Task — the project task runner
- Rust stable toolchain via rustup
- Python 3.10+ and uv
- Node.js 18+ and pnpm
Getting started
Section titled “Getting started”# Install Task (macOS)brew install go-task
# Clone the repositorygit clone https://github.com/xberg-io/tree-sitter-language-pack.gitcd tree-sitter-language-pack
# Install all language dependenciestask setup
# Build the Rust coretask build
# Run all teststask testOn Debian/Ubuntu, install Task with apt install go-task or download from taskfile.dev.
Common tasks
Section titled “Common tasks”task --list # show all available taskstask build # build Rust core + bindingstask test # run all test suitestask lint # run all linters (clippy, ruff, oxlint, rubocop, …)task format # auto-format all codetask e2e:generate # regenerate e2e test suites from fixturestask e2e:test # run e2e teststask alef:sync # regenerate the alef-managed bindings and docsRun task --list to see all available tasks.
Adding a language
Section titled “Adding a language”The most common contribution is adding a new tree-sitter grammar.
1. Find or create a grammar
Section titled “1. Find or create a grammar”The grammar must:
- Be permissively licensed — MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, or Unlicense only. We do not accept GPL, AGPL, LGPL, MPL, or any copyleft license. This ensures tree-sitter-language-pack can be used freely in any project without imposing license obligations on downstream users.
- Have a public Git repository.
- Produce valid
parser.coutput fromtree-sitter generate. - Compile cleanly on Linux, macOS, and Windows.
2. Add the grammar definition
Section titled “2. Add the grammar definition”Edit sources/language_definitions.json and add an entry:
{ "mylang": { "repo": "https://github.com/example/tree-sitter-mylang", "rev": "abc123def456", "branch": "main" }}Always pin to an exact commit (rev), not a branch tip. This ensures reproducible builds.
Available fields:
| Field | Required | Description |
|---|---|---|
repo |
Yes | Grammar repository URL |
rev |
Yes | Exact commit SHA to pin |
branch |
No | Branch name (used by scripts/pin_vendors.py to find latest) |
directory |
No | Subdirectory within the repo containing the grammar |
extensions |
No | File extensions that map to this language (e.g. ["rs"]) |
ambiguous |
No | Extensions shared with other languages (e.g. {"h": ["cpp", "objc"]}) |
c_symbol |
No | Override for the C symbol name when it differs from the language name |
generate |
No | Set to true to force running tree-sitter generate before compiling |
3. Build and test
Section titled “3. Build and test”# Compile the new parsertask build
# Run the test suitetask test
# Verify the parser works end-to-endts-pack download mylangts-pack parse example.mylang --language mylang4. Add test fixtures
Section titled “4. Add test fixtures”Add at least one fixture under fixtures/. Fixtures are the single source for both the e2e
suites and the documentation snippet corpus — task e2e:generate renders each fixture into
docs-site/src/snippets/generated/<lang>/<category>/<id>.md for all 14 bindings. Do not
hand-write snippets; add a fixture instead.
A fixture file holds either a single JSON object or an array of them, grouped into a
per-category directory — for example fixtures/process/python_intel.json. Only id and
description are required, additionalProperties is false, the payload goes under input,
and assertions is a list of typed assertion objects, not a map of booleans. See
fixtures/schema.json for the full assertion-type enum.
{ "id": "mylang_function_process", "description": "Intel: extract structure from a mylang function definition", "category": "process", "tags": ["intel"], "input": { "source_code": "// example mylang source", "config": { "language": "mylang" } }, "assertions": [ { "type": "equals", "field": "language", "value": "mylang" }, { "type": "count_min", "field": "structure", "value": 1 }, { "type": "equals", "field": "metrics.error_count", "value": 0 } ]}Then regenerate and run e2e tests:
task e2e:generatetask e2e:test5. Open a pull request
Section titled “5. Open a pull request”- Title:
feat: add <language> parser - Body: link to the upstream grammar repository, note any quirks or limitations
Fixing a bug
Section titled “Fixing a bug”- Check the issue tracker — the bug may already be reported.
- Write a failing test that reproduces the issue.
- Fix the bug in the appropriate crate.
- Confirm all tests pass with
task test. - Open a PR with a clear description of the root cause and fix.
Improving bindings
Section titled “Improving bindings”Binding improvements (better error messages, idiomatic APIs, new methods) are
welcome. Compiled binding crates live under crates/ (ts-pack-core-py, ts-pack-core-node,
ts-pack-core-php, ts-pack-core-wasm, ts-pack-core-ffi, tree-sitter-language-pack-jni);
the host-language packages they feed live under packages/. See the
Architecture page for the full crate layout.
Binding changes must:
- Not add logic that belongs in the Rust core. Bindings are pure translation layers.
- Have test coverage in the binding’s native test suite.
- Follow the existing API surface — most binding surfaces are alef-generated; regenerate
them with
task alef:syncrather than hand-editing generated files.
Documentation
Section titled “Documentation”Doc fixes and new guides follow the same workflow as code changes:
- Fork and create a branch.
- Edit files under
docs-site/src/content/docs/. Runnable snippets are generated fromfixtures/intodocs-site/src/snippets/generated/<lang>/— change the fixture and reruntask e2e:generate, never edit a generated snippet. - Preview locally with
pnpm --dir docs-site dev(the site is Astro / Starlight). - Run
task lintif you touch any scripted checks. - Open a pull request.
Use the Edit button in the page header to jump directly from any docs page to the matching file on GitHub.
Code quality
Section titled “Code quality”The project uses pre-commit hooks managed by prek:
prek installprek install --hook-type commit-msgBefore committing, verify these three commands pass:
task lint # zero warnings requiredtask test # all tests must passtask format # code must be formattedCommit style
Section titled “Commit style”Follow Conventional Commits:
feat: add kotlin parserfix: correct memory layout in Java FFI array freeingchore: update tree-sitter to 0.25docs: add chunking guidetest: add e2e fixtures for rubyKeep commits small and focused. Each commit should represent one logical change.
Pull request checklist
Section titled “Pull request checklist”-
task testpasses -
task lintpasses (zero warnings) - New language has at least one fixture under
fixtures/, with the regenerated snippets underdocs-site/src/snippets/generated/committed alongside it -
task e2e:generate && task e2e:testpasses -
task version:syncrun if any manifest was bumped - PR description explains the change and links related issues
Getting help
Section titled “Getting help”- GitHub Discussions — questions and design conversations
- Discord — real-time chat with maintainers
- Issue tracker — bug reports and feature requests