7.6 KiB
Code map: where to edit (for agents)
Read this instead of exploring. docs/ARCHITECTURE.md has the crate-level design and status; this file says which FILE to open for which change. Rules: AGENTS.md, .claude/rules/*.md, specs/agents/minimax-m3-1-flash.md. Verified against the tree on 2026-10-20: if a path below is gone, git grep the symbol, then fix this file.
Layers and crates (cargo xtask layers enforces)
L0 vault markdown | L1 index canvas diagrams whiteboard annotate sync collab blocks pdf | L2 backlinks graph templates lint knowledge | L3 plugins themes calendar | L4 engine | L5 editor mcp i18n | L6 ui-egui. Apps: apps/notescraft (desktop shell, launcher host), apps/notescraft-cli, apps/notescraft-sync-server (axum + rusqlite, exempt from layers). Nothing below L5 may use egui.
Engine (crates/engine/src, package notescraft-engine)
Everything user-visible is a command (id, label, params, enabled, run) in a Registry<Session>.
| Want | Open |
|---|---|
| Register a command group | the group's specs()/register_x(reg); add ONE call in commands.rs::register_core (list near the top, register_* calls after the loop) |
| Command shape, params validation | spec.rs, params.rs, a finished group to copy: capture/, viewers/, share/commands.rs, review/commands.rs |
| Which commands an AI assistant may call | ai/assistant_gate.rs (READ list vs WRITE list: add every new id) |
| Command list test | tests/core_commands.rs (CORE_IDS) |
| Errors | error.rs (one Error enum, add variants there; thiserror) |
| Session, buffers, open files | vault/ (session.rs, buffers.rs, attachments.rs, pdf_preview.rs) |
| Settings (add a key) | prefs/*_config.rs (struct + defaults + validation), prefs/catalog/ (listing), test like tests/files_config_viewers.rs |
| Server account, share, publish, invites | share/ (client.rs = blocking ServerClient, commands.rs, publish.rs, history.rs, bind.rs) |
| Sync client, queue, conflicts | sync/ (worker.rs, commands.rs, conflicts.rs) |
| Live co-editing | live/ |
| Comments, suggestions, mentions | review/ (model, sidecar, anchor, suggestion, store, commands, merge) |
| File viewers backend | viewers/ (file.info, file.hash, file.neighbours, image.annotations.*) |
Capture (note.capture) |
capture/ |
Engine tests: crates/engine/tests/*.rs, fixtures in tests/common/mod.rs (TempVault), drive the registry, not internals. Test servers: see tests/versions_server.rs pattern in crates/ui-egui/tests/ and tests/publish_stub/ in engine. |
UI (crates/ui-egui/src, package notescraft-ui-egui)
| Want | Open |
|---|---|
| A tab/view kind (file type -> view) | widgets/tabs/kind.rs (TabKind::of, tables, icon()), the dispatch in shell/app/window/views.rs::show (one arm per kind), the view in views/<name>/ |
| An existing view | views/: note_view, canvas_view, diagram_view, whiteboard_view, graph_view, calendar_view, settings_view, image_view (+ annotate/), media_view (video, pdf, audio/ = tab, embed card, waveform, live spectrum, own FFT, ffplay player; bar.rs = shared bar card/buttons), code_view, file_card.rs (info card), folder_view.rs, share_dialog/ (members, invites, publish.rs), versions_view/, trash_view/ |
Bases (.base files) |
pure crate crates/bases (yaml/, expr/, eval/, query/, map/), engine crates/engine/src/bases/ (base.*, maps.*, tiles/ fetcher and cache), the tab views/base_view/ (state.rs queues engine calls and BaseView::pump runs them after the frame, table/, menus/) |
| Map view and Maps settings | views/base_view/map/ (camera pan/zoom ease, tiles bounded texture cache fed by maps.tile, markers pins and clusters, popup card, placeholder and enable notice, grid fallback, zoom buttons and attribution), card views/settings_view/categories/maps.rs, copy text/views/maps.rs ([ui.maps]), tests tests/base_map.rs |
| Side panels | panels/ (tree* = Explorer, sidebar*, right*, search_panel, sync_*) |
| Shared widgets | widgets/ (tabs/, context_menu.rs, palette.rs, bottom_sheet.rs...) |
| App state and frame loop | shell/app/ (window/frame.rs frame, window/commands.rs UI commands and engine_command(id, ¶ms), window/views.rs view state, window/menus.rs, vault/ open/index, sync.rs, live/, editor/ (paste/drop in editor/attachments.rs), video.rs ffmpeg player, audio player ticks from vault/explorer.rs) |
| Keyboard shortcuts, tab/panel focus hotkeys, shortcut text in tooltips | shell/hotkeys/: one table defaults.rs (add a chord there), dispatch.rs (consumes it once per frame), commands.rs (bodies, palette entries), focus.rs (panel landmarks); tooltips call hotkeys::on_hover_hotkey(response, label, id) / hotkeys::tooltip; cargo test -p notescraft-ui-egui --lib hotkeys checks the table for conflicts |
| Attachment paste and drop | shell/attachment_drop/ (collect returns Requests; the app runs the engine command, no vault IO while painting) |
| Compact (phone) layout | shell/compact/, tokens in design/style/compact* |
| Icons | Lucide SVGs in assets/icons/*.svg, registered in design/icons.rs (icon!("name")), drawn with crate::icons::paint(ui, "name", rect, colour); interactive controls use design/lottie_icon.rs |
| Colours, radii, spacing | theme tokens: tokens.theme.colors.* (surface, surface_2, text, text_muted, accent, danger...), design/style.rs; NEVER hex |
| Strings | every string goes through a table: text/<area>.rs or text/views/<view>/mod.rs with table! { name = "ui.area.key"; }, and the key in crates/i18n/locales/en.toml under [ui.area]. New table = append at the END of the [ui.*] tables; never between keys of another table. Check: python3 -c "import tomllib;tomllib.load(open('crates/i18n/locales/en.toml','rb'))", cargo xtask i18n. Lib tests print raw keys? the i18n crate cached an old en.toml: touch crates/i18n/src/i18n.rs |
| Jobs that must not block the UI | worker thread + std::sync::mpsc, polled each frame, ctx.request_repaint_after (copy share_dialog/mod.rs) |
| UI tests | crates/ui-egui/tests/*.rs (egui_kittest, real events through frames; copy share_ui.rs, image_view.rs), unit tests next to the code, helpers testsupport.rs |
| Render a screen to PNG | cargo run -p notescraft-ui-egui --example snapshot -- --vault <v> --out ui.png --size 1440x900 --open "note.md" and READ the PNG |
Designs: design/files/*.png (viewers), design/mobile/*.png; PaperCraft project NotesCraft. |
Server (apps/notescraft-sync-server/src)
api/routes.rs (route table), api/* (accounts, vaults, members, invites), store/ (rusqlite schema + queries), history/, chunks/, live/, publish/ (pages, links, render), activity/ (feed), roles.rs, limits.rs. HTTP tests: apps/notescraft-sync-server/tests/*.rs against a real in-process server.
Gates (run only what you changed, then the whole set before claiming done)
cargo test -p <crate> | cargo clippy -p <crate> --all-targets -- -D warnings | rustfmt --edition 2024 <your files> (never cargo fmt --all in the shared tree) | cargo xtask layers | cargo xtask tree (max 12 loose .rs per dir) | cargo xtask i18n | cargo xtask ci (everything).
Shared tree
Several agents and the owner work in one tree. Edit only the files your brief lists. Uncommitted files of others (check git status) are NOT yours and not part of your build: never depend on them, never fix them, say so in the report.