Files
notescraft/AGENTS.md
T
Marcos Paulo c78fd488cc
ci / ci (macos-latest) (push) Has been cancelled
ci / ci (ubuntu-latest) (push) Has been cancelled
ci / ci (windows-latest) (push) Has been cancelled
feat: registry core (model, guard, verify, store, net, install, commands), registry browser UI, signing tool, size profile and font dedupe, lazy Hebrew/Arabic fonts, htmlmd/srs/textdiff crates
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-21 17:28:10 -03:00

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>, package notescraft-<name>, [lints] workspace = true, registered in the root [workspace.dependencies] and in xtask/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: L0 vault markdown; L1 index canvas diagrams whiteboard; L2 backlinks graph templates; L3 plugins themes; L4 engine; L5 editor mcp i18n; L6 ui-egui.
  • Shared crates come from craft-libs (craft-atomic, craft-settings, craft-ui, craft-quit, craft-print), pinned by git rev in the root Cargo.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)]. unsafe is 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 explicit write_private for .notescraft/).
  • No silent panics across the plugin boundary: traps, fuel exhaustion and memory limits become Errors.

Code style

  • One thiserror enum Error and pub type Result<T> per crate. Libraries do not use anyhow.
  • Every public item has rustdoc, every module has a //! comment. clippy::pedantic must 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 .rs files (mod.rs and lib.rs do 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 from lib.rs. Enforced by cargo xtask tree (part of cargo xtask ci); directories still waiting for their restructure are listed in xtask/src/tree.rs and 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 in tests/, benches/perf in perf/ or #[ignore]d tests, examples in examples/. 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).