Files
wordcraft/CLAUDE.md
T
Martin BallandClaude Opus 5.5 3110dcf02b CP1.3: proofing comes from craft-proof (craft-libs), its data from craft-i18n
- wordcraft-proof is now `package = "craft-proof"` from craft-libs (local
  path for now; TODO in Cargo.toml for the git+rev pin after the craft-libs
  PR merges). `wordcraft_proof::` paths are unchanged.
- crates/proof and assets/{spelling,hyphenation} deleted with their
  ATTRIBUTION.md rows; one row now points at craft-i18n's Language data;
  NOTICE paths updated.
- craft-i18n.rev (and the flatpak source) moved to the craft-i18n commit that
  adds language-data/ (CI sets CRAFT_I18N_REQUIRED=1, so the pin must have it).
- xtask layers: proof removed. Engine tests carry their own copy of the
  synthetic Czech fixture (they reached into crates/proof/src).
- Docs: architecture.md, CLAUDE.md/AGENTS.md layer table, README build note
  (CRAFT_I18N_DIR), localization-tr path, ROADMAP progress log.

Before/after wordcraft-cli on a 17-language proofing document: issues,
suggestions, manual hyphenation, PDF text and PDF bytes identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-01 20:13:03 +00:00

9.8 KiB

WordCraft — instructions for agents

WordCraft is a clean-room, open-source, Rust-native word processor targeting Microsoft Word parity — and going further on speed, openness and agent control. It runs natively on macOS, Windows, Linux and BSD, and on the web via WASM. Siblings with the same conventions: ../photocraft (Photoshop), ../vectorcraft (Illustrator), ../filmcraft (Premiere), ../lightcraft (Lightroom), ../pdfcraft (Acrobat), ../effectcraft (After Effects), ../designcraft (InDesign).

Start every session here

  1. Read plan/STATUS.md (current milestone, next task), then the task in plan/execution-plan.md and the relevant plan/architecture.md section. plan/ is gitignored (local only); if it's missing, start from ROADMAP.md, docs/gaps.md and docs/roadmap.md (Current focus).
  2. Follow the autonomous operation protocol (plan/execution-plan.md §5). Don't stop to ask unless a decision is genuinely the owner's (licensing, publishing, pushing to new remotes, secrets).

Never crash

People trust WordCraft with their writing; a crash loses their work. This outranks feature work: never ship a feature through a panic path, and fix a crash before building on top of it.

  • No panics in non-test code: no unwrap(), expect(), panic!, unreachable!, todo!, unimplemented!; no unsafe (unsafe_code = "forbid").
  • Errors are Result<T, E> through the crate's error type and ?. An unfinished feature returns an error or is disabled; it never panics.
  • Input-derived numbers are hostile (files, commands, MCP/control params): get() instead of [i], slice strings only at char boundaries, checked/saturating arithmetic, clamp sizes, cap allocations, bound recursion.
  • Last-resort guard: Session::run turns an escaped panic into an error and restores the document. It's a safety net, not a licence.
  • Prove it: every crash fix lands with a regression test. crates/engine/src/tests.rs::hostile_params_never_panic runs every command with junk params — keep it green.
  • Production crate roots carry #![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]; new crates start with it and add [lints] with workspace = true to their Cargo.toml. Tests may unwrap (clippy.toml).

Assets: absolutely no Microsoft (or Adobe/Avid/Autodesk) iconography or images

This rule is non-negotiable. Breaking it is the worst mistake you can make in this repo.

  • Never copy, trace, screenshot-crop or recreate icons, images, templates, themes, clip art, fonts, cursors, sounds or any other asset from Microsoft Word/Office or any Microsoft, Adobe, Avid or Autodesk product. Not even "temporarily".
  • Every asset must be original (drawn in code — prefer this: crates/ui-egui/src/icons.rs), public domain / CC0, OSI open source, or Creative Commons that allows redistribution, or licensed open source by a contributor who made it.
  • Every asset file has a row in ATTRIBUTION.md (author, source, licence). cargo xtask assets (part of cargo xtask ci) fails otherwise. Add the row in the same commit as the file.
  • Fonts: new font files go to storytold/craft-fonts, never this repo; it's an optional build input (CRAFT_FONTS_DIR). Spelling word lists and hyphenation patterns live in storytold/craft-i18n language-data/, never this repo; they are embedded from CRAFT_I18N_DIR (pinned by craft-i18n.rev, which CI checks out). Without it the app builds but English isn't spell-checked and hyphenation is off, so proofing tests need it. Documents asking for proprietary fonts (Calibri, Aptos, Cambria…) are rendered with installed system fonts or metric-compatible open substitutes (crates/fonts/src/word.rs) — never bundle proprietary fonts.
  • Templates, sample documents and themes are our own text and colours (crates/engine/src/sample.rs, cmd/design.rs). Demo images are public domain, with sources recorded.

Clean room

  • Microsoft Word is installed on the dev machine and may be observed black-box: run it, use its UI with synthetic documents, take screenshots of its window only (by window id — the machine runs other work; never capture the whole desktop) stored only under plan/word/screenshots/ (gitignored, never committed).
  • Never read, disassemble or copy anything inside the Word bundle (file names/listings only). Never commit files produced by Word. Never copy Microsoft wording beyond feature names.
  • File formats come from public specs: ECMA-376 / ISO 29500 (OOXML), the published RTF spec, OASIS ODF 1.3. Never copy GPL/LGPL/AGPL code (LibreOffice, AbiWord, pandoc…).

Architecture (see plan/architecture.md)

Layer Crate Job
L0 geom units, rects, measurement parsing
L1 doc, fonts document model + edit primitives; font DB, shaping, Word font substitution
L2 layout, docx, formats line breaking, pagination, tables, headers/footers, hit testing; OOXML I/O; TXT/MD/HTML/RTF/ODT
L3 render, pdf vello_cpu rasteriser; krilla PDF
L4 engine Session, undo, command registry, Word feature catalog, samples, I/O dispatch
L5 mcp MCP server (headless or bridged to the app)
L6 ui-egui Word-style egui front end (swappable)
apps apps/wordcraft, apps/wordcraft-cli, apps/wordcraft-web binaries
external craft-proof (craft-libs, used as wordcraft-proof, sits at L1) proofing: spelling, grammar, hyphenation; its word lists and patterns are craft-i18n's language-data/ (CRAFT_I18N_DIR)
  • Everything is a command. User-visible behaviour = a CommandSpec in crates/engine/src/cmd/*.rs (id, label, ribbon location, shortcut, params doc, enabled, run) + tests. UI-only commands (ui.*) live in crates/ui-egui/src/lib.rs. The ribbon, shortcuts, command search, CLI, control channel and MCP all dispatch by id. Programmatic calls never open dialogs.
  • Parity is measured: crates/engine/src/catalog.rs lists Word's ribbon/menu features with command ids. cargo xtask parity writes docs/parity-checklist.md; a test enforces a floor that only rises. Implement missing ids to raise it.
  • Layering is enforced by cargo xtask layers. Nothing below L6 depends on egui/eframe/winit/rfd. The UI is thin and reads Session state; colours come from theme::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, tests, assets, layers, wasm). Commit after every arc of work that builds, with a task id in the message (M2.1: line spacing dialog).

Typing behaves like Word

Typing, Enter, Backspace, Tab, lists, AutoCorrect and AutoFormat follow Word's observed behaviour in docs/typing-parity.md, pinned by crates/engine/src/tests/typing.rs (keys go through the same commands as the keyboard). Change behaviour, doc and tests together; a typing fix lands with a test there. Compare headlessly (ui_shot); don't drive GUIs with keystrokes on the shared machine.

Running and looking at the app

  • cargo run --release -p wordcraft -- --sample --control 7981 (sample document + control channel).
  • Drive it with JSON lines on 127.0.0.1:7981, each with the window's key from ~/.config/wordcraft/control-key.local-7981 (macOS: ~/Library/Application Support/WordCraft/), e.g. {"id":1,"key":"…","method":"engine.execute","params":{"command":"text.insert","params":{"text":"Hello"}}} then {"id":2,"key":"…","method":"ui.screenshot","params":{"path":"/tmp/shot.png"}}. Methods: crates/ui-egui/src/control.rs; docs: docs/control-protocol.md (Keys).
  • Headless window screenshots (no focus stealing, works with a locked screen): cargo run --release -p wordcraft-ui-egui --example ui_shot -- script.jsonl (see the example's header).
  • For UI work, look at the result (screenshot, read the PNG) and compare with Word side by side.
  • CLI: wordcraft-cli convert in.docx out.pdf, wordcraft-cli run --template sample --cmd 'select.text={"text":"Studio"}' --cmd format.bold --save out.docx, wordcraft-cli commands, wordcraft-cli parity.
  • MCP: wordcraft-cli mcp (headless) or wordcraft-cli mcp --connect 127.0.0.1:7981 (drives the running app). See docs/mcp.md.
  • Shell gotcha: mv/cp may be aliased interactive — use /bin/mv -f / /bin/cp -f.
  • Parallel agents: separate CARGO_TARGET_DIR per agent; edit only the crates you own; delete your target dir when done (disk).

Roadmap

Progress docs: ROADMAP.md (stage, headline numbers, progress log), docs/target-app-parity.md (the assessment), docs/gaps.md (ranked work list), docs/roadmap.md (milestones, Current focus), docs/architecture.md, and the parity checklists docs/file-format-parity.md, docs/layout-parity.md, docs/typing-parity.md, docs/ui-parity.md, docs/hardware-parity.md, docs/localization-parity.md. When work lands, update the gap, the parity doc and the progress log, and bump each touched doc's status line and revision history.

CI workflows

  • Workflows in .github/workflows/ call the shared workflows in storytold/craft-common-actions at @main, with their inputs and secrets. No other jobs: if no shared workflow does what's needed, it doesn't go here.
  • Don't add or change CI in a feature or fix PR. If the existing workflows can't build or test a change, link an existing craft-common-actions issue or PR, or open a new issue, or a PR only for a small fix that is safe for every app and does not increase CI time.
  • Some workflow files here still run their own jobs. Don't add to them. Moving a job into craft-common-actions is its own task, never part of another PR, and the job stays here until a shared workflow runs it.