bezel-contributing · git:20260908.513dee9 · 2026-09-08 · sha256 db4d2cf762f3cfc3
bezel-contributing git:20260908.513dee9A
Immutable. This exact content is served forever at /api/v1/blob/db4d2cf762f3cfc3.
--- name: bezel-contributing description: Work inside the bezel repo — where code goes across the crate layers, the five laws a change has to obey, and everything a component has to land with (gallery row, docs page, tests, the nightly rustfmt import pass). Use for any edit under crates/, apps/ or www/ in this repository, and before opening a PR against crabtalk/bezel. --- # Working on bezel `CONTRIBUTING.md` is the full text and wins on any conflict. This is the part an agent gets wrong. ## Where code goes ``` crates/theme tokens + appearance (the @Environment layer) crates/motion animation vocabulary crates/ui components (the View layer) crates/icons the icon set (declared from Lucide, no SVGs in git) crates/markdown block document model (pure: doc, parse, serialize, select, edit) crates/blocks painted fenced blocks crates/editor the editing surface (keys, IME, undo, anchors, menus) crates/syntax tree-sitter highlighting (one answer to a seam, never a feature on it) crates/bezel the facade apps/gallery the documentation, live ``` Dependencies point downward only — `ui → motion + theme`, `theme → gpui alone`. A member inherits every dependency (`x.workspace = true`) and never names a version of its own. Nothing new lands in the facade that every app does not paint with; `markdown`, `syntax`, `blocks` and `terminal` stay peers a consumer names. ## The five laws, compressed 1. **Style flows through the environment.** No color, font or size parameters. The environment supplies defaults; a caller overrides by chaining gpui modifiers on what is returned — so never bake style into a child the caller cannot reach. The rare exception takes an optional `StyleRefinement` merged last. 2. **SwiftUI vocabulary.** Name a widget for its SwiftUI analog. Stateless paint is a catalog trait on `Theme`; stateful is a struct entity whose builders configure *content*. A closed enum picks between shipped looks — free-form radius, color and padding never become parameters. 3. **Motion is named.** From the `MotionSpec` catalog; phase math lives in `motion::phase` and is unit-tested. No inline durations or curves. 4. **Numbers drive layout, colors are paint.** No layout value depends on which color is painted. A number reaches `Theme` only when the platform names it; a component's own metric stays with the component. 5. **Measured, and dated.** Every number on `Theme` records where it was read and when. Where the platform names one value, ship one and no more — inventing the rest puts made-up numbers in the file and every later decision rests on them. Extracted from working application code, never invented ahead of need. If there is no consumer, it does not land. ## What a change lands with - **A gallery row.** `apps/gallery/src/lib.rs` `TABS` — key, title, and the source path it prints as documentation. `apps/gallery/tests/rail.rs` asserts keys are unique and every path exists. - **A docs page.** `www/docs/<key>.md`, frontmatter `title` + a one-line unique `description`. The site indexes prose by rail key, so a row without a page is a broken build, and the page is what `llms.txt` and `llms-full.txt` serve to agents. - **Tests.** Pure logic gets unit tests (`motion::phase`, `markdown` round-trips to a fixed point). Prefer a test that proves the artifact works over one that proves it looks like markup. - **Terse docs.** Doc comments say what the thing is and why it is that way. No essays. ## Commands ```sh cargo nextest run # the suite — never cargo test cargo clippy --workspace --all-targets # CI runs with -D warnings cargo run -p gallery # every component, live cargo build -p web --lib --target wasm32-unknown-unknown # CI's third leg ``` After touching imports, stable rustfmt cannot group them per crate ([rustfmt#4991](https://github.com/rust-lang/rustfmt/issues/4991)): ```sh rustfmt +nightly --edition 2024 --config imports_granularity=Crate <files> cargo fmt --all ``` CI is fmt + clippy on Linux, `nextest --no-fail-fast` on macOS *and* Linux, and a wasm build. Linux is the platform with no lens that must still pass; wasm is where `std::time::Instant` panics and a missing renderer feature first shows up. ## Pull requests One-line Conventional Commits subject (`feat(editor): tab indents and zoom support`) — no body, no trailers, no AI attribution. PR body is a few lines or short bullets. Branch, never push to `main`.