Contributing to K2F
Thank you for helping. We care about deterministic layout, honest integrity reporting, and keeping the spec, schemas, and engine aligned.
Repository: github.com/suzheng/k2f · Community hub: k2f.dev/community · Conformance (golden runner): k2f.dev/conformance
Ways to contribute
| Area | Where to work | What helps |
|---|---|---|
| Bugs and ideas | GitHub Issues (use the templates) | Minimal .K2F, repro steps, spec impact for format changes |
| Author docs and spec | docs/ in this repo | Guides, spec (docs/spec/), architecture notes for contributors |
| Agent skill | k2f — skills/core/k2f/ | Workflows, catalog (ex_*.json), skill schemas, scripts |
| Engine, CLI, exporters, viewer | This repo (engine/, cli/, export/, sdk/) | Rust/Python/JS changes with tests |
Security vulnerabilities: SECURITY.md — not public issues.
Prerequisites
- Rust (latest stable) — rustup.rs
- Python 3.9+ —
k2f_py/ maturin when testing the Python SDK - Node.js 18+ — when changing
sdk/jsor running JS tests
See COMPATIBILITY.md for engine version matching and supported runtimes.
Development setup
Clone and build the toolchain used by contributors and CI (no PyPI install required first):
git clone https://github.com/suzheng/k2f.git
cd k2f
bash scripts/dev-install.sh
bash scripts/test-getting-started.sh
dev-install.sh creates a venv under sdk/python/.venv, builds the Python package with maturin, and compiles JS WASM bindings. The smoke script writes a package, exports PDF, checks PDF_IS_NOT_A_SOURCE, and runs k2f verify.
On Windows, use Git Bash or WSL for the bash scripts. Rust is required.
cargo build
cargo test
Documentation (single sources of truth)
| Content | Edit here | Published as |
|---|---|---|
| Human docs (guides, authoring, spec) | docs/ | Copied into sdk/js/public/ via symlinks; shipped in @openk2f/k2f and shown on k2f.dev/docs |
Agent skill (catalog, SKILL.md, skill schema/) | skills/core/k2f/ in this repo | npx skills add suzheng/k2f --skill k2f · k2f.dev/skills/k2f |
| Install pointer | skills/README.md | Registry and install overview |
| Format JSON Schema | schema/ at repo root | Validators in Rust; skill schemas should stay in sync |
Do not edit files under sdk/js/public/ by hand — in a git checkout they symlink to docs/, schema/, skills/README.md, and meta/; npm pack materializes copies into the tarball.
After changing markdown under docs/ or repo meta files:
bash scripts/check-doc-links.sh
Build and test
Golden suite
Lock comparison is geometry + render plan + content hash. Engine commit SHA and appearance_hash are not golden-equal (they differ between debug UNKNOWN and release git SHA).
Local (fast): one compile per case, no PNG. Default when CI is unset:
cargo run -p k2f-test-runner -- run
cargo test -p k2f_sdk -p k2f_package -p k2f
CI: five compiles per case (determinism) plus a small PNG appearance gate (elevation_shadows, card_variants, running_footer_page_numbers). Published examples (examples/published/*.K2F) are not PNG-golden.
Visual-gate PNG (optional locally):
cargo run -p k2f-test-runner -- run --check-png --dataset-runs 1
Cases without committed page_*.png skip the pixel check. To refresh gate PNGs: --update --check-png.
Default cargo test -p k2f_paint still renders those scenes and checks PNG magic bytes, but does not byte-compare goldens (macOS vs Linux raster bytes can differ). Linux CI compares via CHECK_PAINT_GOLDENS=1 and the --check-png job. Refresh paint-crate goldens with UPDATE_PAINT_GOLDENS=1.
Nightly: same determinism + PNG gate; see .github/workflows/golden-nightly.yml.
JS / WASM (viewer changes)
bash scripts/build-sdk-js.sh
cd sdk/js && npm test
Doc and spec checks
bash scripts/check-spec-paths.sh
bash scripts/check-doc-links.sh
Official pixels
Never use browser fillText or CSS flow for document body text. The web viewer paints from the WASM lock executor only. Regression test: sdk/js/test/no-fill-text.mjs.
Format schema changes
Repo-root schema/ is the format contract (manifest, nodes, styles, visual_primitives, signatures). Agent dialects live under engine/k2f_sdk/profiles/; MCP catalog at engine/k2f_mcp/mcp_tools.json.
When changing format schema/*.json:
- Update Rust validators in the same PR
- Update
docs/spec/k2f-v0.3.md - Regenerate committed examples if needed (
bash scripts/build-published-examples.sh) - Keep k2f skill
schema/aligned when the format contract changes
Pull request checklist
- Tests pass locally (
cargo run -p k2f-test-runner -- runplus crate tests above) - Spec updated if format or verify codes changed
- Doc links check if you touched
docs/or meta markdown - No secrets, keys, or
.envfiles committed - No
fillText/ CSS-flow regression in the viewer
Releasing (maintainers)
Do not publish from a laptop using scripts/archive/local-publish/.
Do release through GitHub Actions (.github/workflows/publish.yml):
- Work on feature branches; squash-merge into
main, thengit checkout main && git pullbefore bumping or tagging. - Bump versions and update
CHANGELOG.md. bash scripts/publish-preflight.sh- Optional:
bash scripts/trigger-publish-dry-run.sh(wheels only, no registry upload) git tag vX.Y.Z && git push origin vX.Y.Z— publishes crates.io, npm, and PyPIgh release create vX.Y.Zwith notes fromCHANGELOG.md(tag push does not create a GitHub Release)- Website: bump
dependencies.k2f(npm:@openk2f/k2f@^…) in k2f-site,npm install, test, and deploy — the tag workflow does not update k2f.dev
Full maintainer checklist (including Linux smoke and site steps): bash scripts/publish-all.sh. Background: scripts/archive/local-publish/README.md.
Code of conduct
See CODE_OF_CONDUCT.md.