Contributing

Development setup

Prerequisites

ToolVersionPurpose
Rust1.80+Build all crates
Node.js20+Build the VS Code extension
TypstlatestDocument rendering in tests
TinymistlatestNeeded by the LSP
R4.0+Run R executor tests
Python3.8+Run Python executor tests

R and Python are optional for unit tests but required for integration tests.

Clone and build

git clone https://github.com/knot-literate-programming/knot.git
cd knot
cargo build --release

Binaries: target/release/knot and target/release/knot-lsp.

Build the VS Code extension

cd editors/vscode
npm install
npm run compile

Install a development build into VS Code:

bash scripts/install-vscode-dev.sh

This packages the extension into a .vsix file and installs it via code --install-extension. Restart VS Code to activate.


Before opening a PR

Run the same checks as CI, in this order:

# 1. Check & Lint
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings

# 2. Tests (excluding knot-cli integration tests)
cargo test --workspace --exclude knot-cli

# 3. VS Code extension
cd editors/vscode && npm ci && npm run compile

All three must pass with no warnings before pushing.


Commit conventions

Knot uses Conventional Commits:

feat: short description of the new feature
fix: description of the bug that was fixed
docs: documentation change
refactor: code change without behaviour change
test: add or change tests
chore: build system, dependencies, CI

Scope is optional but helpful for larger PRs:

feat(lsp): add Go to Definition for Typst symbols
fix(executor): set KNOT_FIG_FORMAT env var in Python process

Project structure recap

crates/
  knot-core/
    src/
      parser/          # Winnow-based .knot parser
      compiler/        # Three-pass pipeline
        pipeline.rs    # Pass 1: planning + hashing
        execution.rs   # Pass 2: parallel execution
        mod.rs         # Pass 3: assembly + two-phase API
        freeze.rs      # Freeze contract checking
        snapshot_manager.rs
        node_output.rs
        options.rs
        sync.rs        # #KNOT-SYNC markers
      executors/       # R and Python subprocesses
      cache/           # SHA-256 addressed persistent cache
      backend.rs       # Node → .typ text rendering
      project.rs       # Top-level compile_project_* API
      config.rs        # knot.toml parsing
  knot-cli/
    src/main.rs        # CLI command dispatch
  knot-lsp/
    src/
      server_impl.rs   # Request/notification handlers
      state.rs         # ServerState (Arc<RwLock<>>)
      proxy.rs         # Forward to Tinymist
      position_mapper.rs
      diagnostics.rs
      handlers/        # Completion, hover, formatting
      sync.rs          # Forward/backward sync
editors/
  vscode/
    src/
      extension.ts     # Activation, preview lifecycle
      projectExplorer.ts
resources/
  typst.R              # Embedded R helper (typst(), current_plot())
  typst.py             # Embedded Python helper

Adding a new language executor

See Language Executors for the complete checklist.

Adding a chunk option

See Adding a Chunk Option for the complete walkthrough.


Releasing

Releases are automated via cargo-dist. Pushing a version tag triggers GitHub Actions to build binaries for all supported platforms and publish a GitHub Release with the binaries and the VS Code .vsix.

# Bump version, tag, and push (triggers CI + release)
git tag v0.4.0
git push origin v0.4.0