mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-14 19:26:56 -04:00
Shipped code no longer unwraps, expects or panics: every one of the 124 unwrap()/expect()/panic!/unreachable! sites outside tests now handles the failure (Result/Option, ?, let-else, defaults) and reports errors to the user. - Lints: workspace clippy denies unwrap_used, expect_used, panic, todo, unimplemented and unreachable; clippy.toml allows them in tests, and integration tests, examples and testkit opt out explicitly. - Safety net (vectorcraft_engine::guard): a panic in a top-level command rolls the document back and returns EngineError::Internal; a panicking tool is reset; the MCP server answers with an internal error and keeps serving; the UI frame and each control request are guarded. - APIs that hid failures now return them: Rendered::to_png/to_jpeg/to_webp return Result (JPEG/WebP errors used to write empty files), FontDb::face returns Option, Region::top returns Option. - Fuzzing: engine/tests/import_fuzz.rs feeds garbage, hostile and mutated SVG and PDF through import → render → export (30k cases locally, no panics). - Docs: AGENTS.md/CLAUDE.md rule, docs/development.md "Robustness" section, README pointer and a PR template checklist. Co-Authored-By: Claude Opus 5.5 <[email protected]>
7.4 KiB
7.4 KiB
VectorCraft — instructions for agents
VectorCraft is a clean-room, open-source, Rust-native vector illustration app targeting Adobe Illustrator parity (and beyond). It runs natively on macOS, Windows and Linux, and on the web via WASM. Siblings: ../photocraft (Photoshop-class) and ../printcraft (Acrobat-class); same conventions.
Formerly DrawCraft (renamed 2026-10-01): old .drawcraft files and "format": "drawcraft" headers still open (vectorcraft_format::LEGACY_EXTENSION), and preferences migrate from the old config folder. Keep those paths working; use the new name everywhere else.
Start every session here
- Read
plan/STATUS.md(current milestone, next task), then the task inplan/execution-plan.md§3 and the relevantplan/architecture.mdsection. Behaviour reference:plan/illustrator/*.md. - Follow the autonomous operation protocol (
plan/execution-plan.md§7): orient → plan → implement + test → verify → record → commit. Don't stop to ask unless §7 lists the decision as the user's.
plan/ is gitignored (local only).
Non-negotiables
- Clean-room. Never read, disassemble or copy anything inside the Illustrator bundle (names/listings only). Never copy Adobe icons, artwork, presets or wording beyond feature names. Behaviour comes from public docs and black-box observation of the running app with synthetic documents only (screenshots by window id, stored under
plan/illustrator/screenshots/, never committed). Never copy GPL/AGPL code (Inkscape, lib2geom…). - Assets: no Adobe iconography or images — ever (absolute rule, from the project owner).
- Never add, copy, trace, redraw-from, embed or ship any icon, image, artwork, cursor, preset, swatch/brush/symbol/pattern/style library, ICC profile or screenshot from Adobe products or from any other source whose licence doesn't allow it.
- Every image, icon, font or other asset must be one of:
- original work created for VectorCraft by a contributor (who licenses it MIT OR Apache-2.0);
- OSI open source;
- public domain / CC0;
- Creative Commons with redistribution allowed.
- Every asset file must have a row in
ASSETS.md(path, author, source URL, licence, notes). Put licence texts next to the assets (e.g.assets/fonts/OFL-*.txt) and summarize them inNOTICE. cargo xtask assets(run bycargo xtask ci) fails on any unattributed asset.- Code and original assets are MIT OR Apache-2.0 (
LICENSE-MIT,LICENSE-APACHE,NOTICE). The ArtCraft logos indocs/brand/are trademarks, not open source, underdocs/brand/LICENSE-brand.txt: never modify them or use them outside VectorCraft. - Prefer art generated in code for defaults (swatches, brushes, symbols, patterns, cursors). If the provenance of an asset is unclear, don't add it.
- Reference screenshots of Illustrator stay local under the gitignored
plan/and are never committed, published or used as assets.
- Never crash: no panics in shipped code. A crash loses the user's unsaved work. Files, pasted data, MCP and control messages, and command params are all untrusted input.
- Fallible work returns
Result(orOption); callers handle it or propagate it with?. Failures reach the user as an error message (EngineErrorfor commands, the crate's own error type orStringbelow the engine), never as an abort. - Workspace clippy lints ban these outside tests, so
cargo xtask cifails on them:unwrap(),expect(),panic!,unreachable!,todo!,unimplemented!. Use instead:?,.ok_or(…)?,let … else { return … },if let,unwrap_or/unwrap_or_default/unwrap_or_else,.first()/.last()/.split_last(), and a real error for a match arm you believe is impossible. - Don't panic implicitly either: use
.get(i)instead ofv[i]or&s[a..b]when the index comes from data. Don't divide integers by something that can be zero, cap sizes and counts read from input (allocations, images, loops), and check that floats are finite before casting them or looping on them. - Don't silence errors just to satisfy the lint: use
let _ =or.ok()only where ignoring the failure is the right behaviour, with a comment saying why. - Tests may unwrap and panic (
#[test],#[cfg(test)],tests/,testkit). Integration-test files start with an#![allow(…)]for that. vectorcraft_engine::guardis the last line of defence. Every entry point (commands, tool events, MCP requests, the UI frame, control requests) catches a panic, rolls the document back and reports an internal error. It exists for bugs and doesn't replaceResult: wasm aborts on panic, so the web app has no safety net.- Untrusted input is fuzzed (
engine/tests/import_fuzz.rs,engine/tests/command_sweep.rs,format/tests/prop_format.rs,mcp/tests/protocol_props.rs). Extend these when you add an importer, a parser or a protocol method.
- Fallible work returns
- Everything is a command. User-visible behaviour = a command in
crates/engine/src/cmd/*(id, label, menu path, shortcut, params doc,enabled,run) + tests. Tools emit commands (Begin/Preview/Commit). UI-only commands live incrates/ui-egui/src/menus.rs(UI_COMMANDS). The control channel and MCP reach all of them. - Layering is enforced by
cargo xtask layers. Nothing below L6 depends on egui/eframe/winit/rfd. - The UI is thin: panels read engine state and act through
app.run(id, params). Colours come fromtheme::Tokens. - Rust only (no handwritten JS/TS). Never break wasm (
cargo xtask wasm). - Quality gates before every commit:
cargo xtask ci(fmt, clippy -D warnings including the no-panic lints, tests, layers, wasm). One task id per commit (M2.1: pen tool).
Running and looking at the app
cargo run --release -p vectorcraft -- --control 7979 [file.svg|file.vectorcraft](sibling apps' agents use the same default port: if the log says it failed to bind, pick another port — otherwise your requests reach a different app).- Drive it: JSON lines on
127.0.0.1:7979, e.g.{"id":1,"method":"engine.execute","params":{"command":"shape.rectangle","params":{"x":10,"y":10,"width":100,"height":50}}}then{"id":2,"method":"ui.screenshot","params":{"path":"/tmp/shot.png"}}. Methods:crates/ui-egui/src/control.rs. - For UI work, look at the result (take
ui.screenshot, read the PNG) and compare withplan/illustrator/02-ui-ux.md/10-observed-ui.md.ui.screenshotneeds a presented frame: if it errors (screen locked), check the art withui.render/vectorcraft-cli run … --export x.png, and cover panels with a headless egui frame test (seepanels/transparency.rstests). - Performance:
vectorcraft-cli perfchecks the budgets (render/pan/zoom, hit test, save/open, SVG, Pathfinder) on a synthetic 50k-path document;vectorcraft-cli bench FILEtimes one file. Run them before and after renderer, format or geometry changes, on an idle machine (the report warns when the load average makes timings noise). - MCP:
vectorcraft-cli mcp(seedocs/mcp.md). - Shell gotcha:
mv/cpare aliased interactive here — use/bin/mv -f//bin/cp -f. - Parallel agents: separate
CARGO_TARGET_DIRper agent; edit only the crates you own; write manifests atomically. Each target dir grows to ~30 GB: delete yours when you finish (a full disk fails links witherrno=28).
Roadmap
ROADMAP.md (committed) tracks status, milestones and time-to-parity estimates. Update it whenever a milestone task lands.