the cms for static site generators on atproto
lichen.page CONTRIBUTING.md
6.0 kB · 142 lines
Markdown
at main

Contributing #

Lichen is a CMS for static site generators, with realtime collaboration and ATProto integration. Code, documentation, bug reports, and usability improvements are welcome.

Before committing #

Keep changes focused. Describe the problem, the resulting behavior, and how you verified it in the pull request.

Production error handling #

Propagate or explicitly handle recoverable failures, normally with Result and ?. Do not use expect, unwrap, panic! or an assertion as error handling. At task and HTTP boundaries, report the error and complete or close waiting requests. Never carry a lock guard or guard-bearing poison error through an async/public error boundary. Tests may assert fixture outcomes or deliberately panic in a joined helper thread. The rebuild module denies Clippy's unwrap, expect and panic lints outside tests; legacy sites elsewhere remain follow-up work, not evidence that the repo is panic-free.

Development #

The Nix development shell provides the Rust toolchain and tools used by the gate:

nix develop

# Build the unified client/server executable
cargo build -p lichen-cli --bin lichen

# Run the local site manager, then visit http://127.0.0.1:9000/
cargo run -- server run

# Or serve a single site directory
cargo run -- server run --site ./site

# Format Rust code, then run the PR gate
just fmt
just gate

just gate checks formatting; it does not fix it. just crates shows which crates it selects for linting and why, and just --list lists the available commands. The gate shares its feature selection with the test harness in e2e/lib/features.env; use it to check feature-gated code as well as the defaults.

The lint comparison defaults to review/main. If your checkout uses another remote or target branch, set GATE_BASE to the branch you are contributing to, for example GATE_BASE=origin/main just gate.

For a quick targeted Rust test while iterating, use cargo test -p lichen-cms <test_name>, adding the relevant features when needed. Run just gate before submitting the change.

Testing #

just gate is the normal check for small changes. Full end-to-end coverage is reserved for release preparation or a planned, focused test pass:

# Full workspace gate (excluding the desktop crate)
just gate-all

# Behavioral end-to-end suites
just e2e standard

# Separate feature matrix; not included in the behavioral suites
just e2e feature-matrix
just e2e feature-matrix --full

Start with e2e/TESTING.md for current test selection and setup. The normal gate excludes lichen-tauri, which needs additional desktop system libraries. Use nix develop .#tauri when working on the desktop app and verify those changes separately.

Nix and dependencies #

Without Nix, start with the toolchain in rust-toolchain.toml, including rustfmt and clippy. The gate also needs tools such as just, Git, Node.js, jq, and Hugo; the default shell in flake.nix is the maintained list of development dependencies.

Cargo features select optional functionality, including Hugo, mdBook, and iroh. See README-extended.md and the CLI manifest for the feature definitions.

When changing dependencies, update Cargo.lock alongside the manifests. Git dependency updates may also require changing cargoLock.outputHashes in flake.nix. For dependency or packaging changes that affect the Nix package, verify with:

nix build .#lichen

If Nix reports a fixed-output hash mismatch after an intentional dependency update, update the corresponding hash and rerun the build. The package disables its test phase, so a successful Nix build does not replace just gate.

Documentation #

README.md covers the quickstart and basic usage; README-extended.md covers the command reference and hosting. Keep that split when documenting new behavior. Configuration examples live in settings.toml.example, and architecture and protocol details live in docs/.

Update CLI help when commands or flags change. For bugs, include reproduction steps, expected and actual behavior, and the relevant platform, version, and enabled features.

Architecture #

  • crates/lichen-cli/ — the lichen executable, command dispatch, and remote client
  • crates/lichen-server/ — server modes, site management, authentication, and Git integration
  • crates/lichen-cms/ — editor routes, templates, static assets, saves, and static site generators
  • crates/lichen-flat-file/ — confined site-tree access and transactions
  • crates/lichen-yrs/ — collaborative document and synchronization support
  • crates/lichen-iroh/ — optional peer-to-peer transport
  • crates/lichen-shell/ — optional terminal support
  • crates/lichen-tauri/ — desktop application
  • e2e/ — shared test harness and end-to-end suites

Code style and concurrency #

Prefer APIs that enforce correctness over rules every caller must remember. Keep concurrency and lifecycle bookkeeping behind safe accessors rather than adding caller-managed locks.

Read docs/SITE-CONCURRENCY-MODEL.md before changing saves, Git operations, rooms, or anything that writes into a site tree. It defines ownership, lock order, and how the rules are enforced. Use the existing transaction and lifecycle APIs, and update the model when its contract changes.