5.5 KiB
AGENTS.md: guide for AI agents and contributors
NotesCraft is a native, Obsidian-compatible notes app written in Rust only (egui/eframe, no JavaScript, no Tauri/Electron/webview). It is a Craft-suite sibling of PhotoCraft and VectorCraft and follows their conventions. Product name is always NotesCraft in user-facing text; machine names are lowercase (notescraft-*). Read this file, then SPEC.md (the contract), ROADMAP.md (status) and docs/ARCHITECTURE.md (crate map and APIs).
Orientation
| Read | Why |
|---|---|
SPEC.md |
Authoritative requirements, formats, contracts and acceptance table |
ROADMAP.md |
Phase status, what is done, what is next |
docs/ARCHITECTURE.md |
Layers, per-crate public API and status, design decisions |
Workspace rules
- Edition 2024, resolver 3,
rust-version = "1.95". Use rustup stable (PATH="$HOME/.cargo/bin:$PATH"), not an older system cargo. - One crate per concern in
crates/<name>, packagenotescraft-<name>,[lints] workspace = true, registered in the root[workspace.dependencies]and inxtask/src/layers.rs. - Layering is enforced by
cargo xtask layers: a crate may depend only on strictly lower layers; nothing below L5 may use egui, eframe, winit or rfd. Layers: L0vaultmarkdown; L1indexcanvasdiagramswhiteboard; L2backlinksgraphtemplates; L3pluginsthemes; L4engine; L5editormcpi18n; L6ui-egui. - Shared crates come from craft-libs (
craft-atomic,craft-settings,craft-ui,craft-quit,craft-print), pinned by git rev in the rootCargo.toml. Do not change their API; ask first. - A new third-party dependency needs a written reason and owner approval. Already approved:
notify,pulldown-cmark,toml,wasmi,wat(dev),thiserror,serde,serde_json, and for sync (2026-10-19):sha2,axum,tokio,ureq(rustls),rusqlite, and for paste (2026-10-20):arboard(image-data),image(png feature only), and for the registry (2026-10-21):ring(ed25519 verify, already linked through rustls).
Never crash (outranks features)
- No
unwrap(),expect(),panic!,todo!,unreachable!,unimplemented!in non-test code. Every crate keeps#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)].unsafeis forbidden. - Input-derived numbers are hostile: use
get()/split_at_checked, never[i]or[a..b](even when guarded);checked_*/saturating_*; cap allocations; bound recursion (depth limits or iteration). - Invalid input returns
Err. Never silently clamp, truncate or "fix" it. - Reserved vault paths
.obsidian/and.notescraft/are never written through public APIs (except the explicitwrite_privatefor.notescraft/). - No silent panics across the plugin boundary: traps, fuel exhaustion and memory limits become
Errors.
Code style
- One
thiserrorenumErrorandpub type Result<T>per crate. Libraries do not useanyhow. - Every public item has rustdoc, every module has a
//!comment.clippy::pedanticmust be clean; no blanket allows. - Files stay under about 400 lines; split by concern. Smallest design that works; no speculative abstractions.
- Source folders stay shallow and grouped: no directory under a crate's
src/(or an app's) holds more than 12 loose.rsfiles (mod.rsandlib.rsdo not count). Group files into sub-folders by concern (foo.rs+foo/), and nest a group inside a parent folder when it grows. Moving files must not change public paths: re-export fromlib.rs. Enforced bycargo xtask tree(part ofcargo xtask ci); directories still waiting for their restructure are listed inxtask/src/tree.rsand in ROADMAP.md. - Named exports,
import type-style discipline, no magic numbers (named constants),get= derived,fetch= IO,is/has/can= predicate. - Tests: unit in
src, integration intests/, benches/perf inperf/or#[ignore]d tests, examples inexamples/. Write the failing test first. Every crate has at least one. - Every write to disk goes through
craft-atomic.
Before you finish a task
export PATH="$HOME/.cargo/bin:$PATH"
cargo test -p notescraft-<crate>
cargo clippy -p notescraft-<crate> --all-targets -- -D warnings
cargo fmt -p notescraft-<crate>
cargo xtask ci # fmt --check, clippy -D warnings, test, layers: must be green
run cargo xtask i18n and do not add hardcoded user strings.
Check that every module is declared in lib.rs and that its tests actually run. After finishing, update ROADMAP.md and docs/ARCHITECTURE.md (status, public API, numbers). Commit only when the owner asks.
Everything is a command
User-visible behaviour is an engine command (id, label, params, enabled, run) so the UI, CLI, control channel, MCP and plugins share one surface (SPEC 10). The engine crate does not exist yet; until it does, keep logic in pure library crates that a command can call.
Design
Check UI changes visually: cargo run -p notescraft-ui-egui --example snapshot -- --vault <vault> --out ui.png --size 1440x900 --open "folder/note.md" renders offscreen; read the PNG and compare with the PaperCraft design (also --theme catppuccin-latte, --scale 2).
Design reference: PaperCraft project NotesCraft (tokens, workspace, graph, palette, settings, whiteboard screens). Panels are rounded floating cards on the canvas colour and separate by tone, not borders; Catppuccin Mocha/Latte are the default themes (SPEC 8, 8.1, 8.2).