DesignCraft
Audit basis: this checkout is tag v0.16.0, commit 1fe8885bda7451263879cfbb256b9a3d46c411bf (the v0.15.2 ref was fetched for set diffs). The installed /Applications/DesignCraft.app matches this tag and prints designcraft 0.16.0. Verify against your installed version — the ArtCraft Launcher auto-updates.
v0.15.2 → v0.16.0 is a fix wave with no registry change (engine ids, 26 MCP tools, CLI subcommands and the control dispatch set all re-verified unchanged; the only control-channel code change is behavioural: dialog.open with id frameSize now builds the dialog from the app's current ruler units). What landed: the Type menu separates the CJK commands from Insert Math Expression (#2048); File ▸ Quit joins the in-window menu on Windows and Linux (#2049); spellcheck squiggles follow the text frame's rotation (#2042); macOS Finder opens .indd/.indt with DesignCraft (#2053); parent pages: single-sided pages in a spread show the parent page in their place (#2071), document-page overlays no longer pile onto the parent canvas (#1232) and running headers show their name on the parent itself only (#2057); xref end-tag parsing skips quoted attribute values (#2058); file.importXml keeps the text of nested inline elements (#2061); images refuse a raster that would decode past 1 GiB of RGBA (#1975); EPUB/HTML character styles and overrides keep underline, strikethrough, caps and tracking (#1914); the toolbar's Alt/Option-click cycles the flyout tool group (#2031); the Rectangle dialog sizes in the ruler units, not always picas (#2055); cross-references keep edited text and break at spaces (#1239); and Import warnings ▸ Show selects the frame a story warning is about (#2052). Deep automation detail — CLI flags, script syntax, all 26 MCP tools, the control methods, coordinates, guide and column geometry, layer options, EPUB splitting, shortcut import — is in references/agent-surfaces.md next to this file.
v0.15.0–0.15.2 is a parity/UX wave with no automation-surface change: Alt/Option-click cycles a toolbar flyout's tool group; the Rectangle dialog speaks and reads back ruler units (#1964); Find/Change gained Find Format, Change and Change/Find (#1497/#1498) and a null attribute with an empty Change formats the found text instead of deleting it (#1496); text.move keeps the selected cells so typing inserts at the caret (#1674); spellcheck squiggles follow text-frame rotation (#2042) and suggestions include common words (#1509); the Type menu separates CJK commands from Insert Math Expression (#2043); import warnings' Show selects the story-warning frame; File ▸ Quit joins the in-window menu on Windows/Linux (#2044); cross-references count saved text as generated only on an exact match; XML import keeps nested inline element text; hyphenation handles French/Italian apostrophe elision (#1566); drop caps move with vertical justification (#1461); object.effects patches keep a new inner shadow/glow's default mode (#1451); Direct Selection selects one frame among many and drags anchors in spread space (#1125/#902); screen-reader naming landed for TOC fields, Paragraph Style Options' Next Style and the Color Picker fields.
Overview
DesignCraft is a page-layout and publishing application written from scratch in Rust: "an open-source, modern desktop publishing and page layout studio" (README.md). It aims at full Adobe InDesign 2026 parity — "faster, open (documented JSON format + IDML), scriptable by agents (MCP), and available on the web" (ROADMAP.md) — as a clean-room application (AGENTS.md). It runs natively on macOS, Windows and Linux, and in a browser as WebAssembly (README.md §Web, apps/designcraft-web). The UI migrated to egui 0.37 with craft-ui's shared docking this release. Maturity is pre-alpha: the alpha gate is still blocked by fixes to Smart Text Reflow on the Primary Text Frame (#165), ~5–7 h away (ROADMAP.md:3, docs/gaps.md §0); the maintainers estimate ~80% feature breadth and ~47% "ready for real work" (docs/target-app-parity.md §Headline). Source: GitHub storytold/designcraft, MIT OR Apache-2.0 (Cargo.toml), a layered Cargo workspace enforced by cargo xtask layers; shared craft-libs crates provide printing, ICC colour management, atomic writes, PDF writing (craft-pdf now carries overprint/knockout/CMYK blending and spot gradients, plus the craft-prepress flattener for PDF/X-1a) and document-path policy (Cargo.toml).
The one idea that governs everything: every user-visible action is a command with a stable id and JSON parameters (crates/engine/src/cmd.rs command_specs), and the UI, CLI, control channel and MCP all go through Session::execute (crates/engine/src/lib.rs). Prefer commands over GUI poking.
Capabilities (verified)
Layout, guides and the document model — implemented
- Facing/non-facing spreads, parent (master) pages with page-number markers, sections, layers, and frames typed text / graphic / unassigned; stories threaded across frames and spreads (
crates/doc/src/{page,story}.rs;crates/engine/src/cmd/{layout,thread}.rs). - Document setup, page-size presets (incl. A0–A2 posters), bleed/slug, start page, Page tool for pages of their own size (
layout.documentSetup,layout.pageSize,file.new). - Multi-document tabs:
file.activate {index},document.list, next/previous document (Cmd+F6/Cmd+Shift+F6) —crates/engine/src/cmd/file.rs,crates/ui-egui/src/menus/. - Ruler guides:
guide.add(horizontal/vertical/both; page, spread or liquid guide),guide.list,guide.select,guide.selectAll(Cmd+Alt+G),guide.deselect,guide.move,guide.moveBy,guide.delete,guide.deleteAll,layout.createGuides(crates/engine/src/cmd/guides.rs; caps 10 000 guides, rows/columns ≤ 1000). Guides are selected like objects and a dragged guide snaps along its axis; Shift snaps to ruler ticks (the 10× tick-spacing step is fixed this release), Cmd suspends snapping. - Custom column guides: a page keeps dragged column positions (
Columns.positions,crates/doc/src/page.rs),layout.moveColumnGuide {page, gutter, position, spread?|parent?}, at most 216 columns (MAX_COLUMNS);view.lockColumnGuidesis a document setting, on by default, saved in the document and IDML;view.lockGuides(Cmd+Alt+;) only stops pointer dragging. - Page view history:
view.goBack(Cmd+PageUp) /view.goForward(Cmd+PageDown) retrace page jumps at the current zoom (crates/ui-egui/src/page_history.rs). - Styles (paragraph, character, object, table, cell, groups), swatches (process/spot/tints/gradients), text wrap, corner options, transparency effects, ICC colour management with working spaces and proof setups.
- Interactions: Pathfinder boolean ops, compound/clipping paths, gradients, stroke styles/arrowheads, tables with merges and graphic cells (gradient cell fills now draw as gradients on screen and in PDF, PR #1768), footnotes, endnotes, notes, cross-references, index, TOC, text variables, conditional text, track changes, data merge, XML tags/DTD, articles, object libraries, books, object states, buttons and form fields, page transitions, Flex Layout.
- Generators: QR codes (
object.qrCode), math expressions (math.insert/math.svg), colour themes from a placed image (color.extractTheme), live captions (object.caption). - Graphics: placed rasters, PDF pages, SVG, PSD composites, EPS previews, image clipping paths read from IDML (
crates/images,crates/render,crates/idml/src/import.rs).
Placed PDFs and placed-graphic layer options — implemented, rendering caveat below
- Object Layer Options distinguishes a placed PDF's own defaults from an explicit choice:
object.layerOptions {ids?, hidden: [name], useDefaults?}whereuseDefaults: falsewithhidden: []means explicitly all on, and legacyhidden: []resets to file defaults (crates/engine/src/cmd/pdflayers.rs).object.pdfLayers {id?}lists{name, visible, default, overridden}. - Every explicit choice is validated with one real visibility rewrite per distinct source before any item is edited or undo recorded, so a mixed selection stays atomic and a PDF that lists layers but cannot be rewritten is refused.
- Output honours the choice: plain and PDF/X-4 exports keep vector artwork and optional content with per-placement overrides; booklet and book-merge output included; PDF/A-2b applies the choices to an export-only 300 ppi raster copy; embedded IDML stores a separate PDF variant per placement while external-only IDML export rejects active choices;
file.packagereports a placement whose choice an IDML copy cannot carry. - IDML
GraphicLayerOption/GraphicLayersettings are retained per placement; retention is not layer-aware rendering — read Known limitations before promising appearance fidelity.
Text engine — implemented
- Knuth–Plass total-fit paragraph composer plus a single-line composer, with a shared compose cache; optical kerning measured from glyph outlines (
crates/compose/src/). - Dictionary hyphenation (Moby list + trained Liang patterns), language-dependent quotes, bidi/RTL with kashida and digit substitution, CJK composition with mojikumi/kinsoku, vertical type, ruby, kenten, warichu, tate-chu-yoko.
- Story-level Optical Margin Alignment:
story.options {story?, frame?, opticalMargin?, opticalMarginSize?}sets hanging punctuation/edges for every paragraph of a story except paragraphs withignoreOpticalMargin; the Story panel andtype.selectionAttrs.storyOptionsexpose it, and IDML carriesStoryPreference(crates/engine/src/cmd/text.rs). - Hyphenation Settings (
app.hyphenationDialog) sets limits, zone, the Better Spacing ↔ Fewer Hyphens slider, Hyphenate Capitalized/Last Word/Across Column and Preview as one undo step. - Bulleted/numbered list buttons:
list.bullets/list.numbers {on?}apply InDesign's default hanging indent and remove it again (crates/engine/src/cmd/lists.rs). - Notes:
note.convertFromText {author?},note.next,note.previous, andnote.split(new this release) — Split Note splits a note in two at the insertion point, as in InDesign; deleting a note or converting it to text keeps the caret on the same text; footnote caret edits no longer drop untyped formatting (crates/engine/src/cmd/editorial.rs). - Convert Variable to Text:
variables.convertToTextandvariables.convertAllToText {name}replace each instance with the value it shows on its page; the variable stays defined. - Key Object for alignment:
selection.key {id}makes a selected item the key object (needs ≥ 2 selected);object.align'stodefaults tokeyObjectwhile one is set. - Column rules (now running from the top line's ascent to the bottom line's descent) and Span Columns, Paragraph Rules above/below, Based on Parent, custom anchored objects with Relative to Spine.
- Story Editor depth ruler (new): a depth ruler beside the text with View › Story Editor › Show/Hide Depth Ruler (
view.storyEditorDepthRuler), as in InDesign (crates/ui-egui/src/story_editor.rs, PR #1795). - Fonts: own font DB, shaping (harfrust), outlines (skrifa), variable-font instances,
Document Fontsfolders beside a document (case-insensitive), Type › Reload Fonts (font.reload).
Import / open — implemented
file.open decides by content, not extension (crates/engine/src/cmd/file.rs open_path):
- Native
.designcraft(zip or legacy single JSON) —crates/format. .idmlInDesign Markup imported into the native model —crates/idml/src/import.rs;.indd/.indtconverted to IDML in memory bystorytold/indd-utils(real-file fidelity unmeasured —docs/gaps.md§2).- Placed graphics: PNG, JPEG, GIF, WebP, TIFF, BMP, PSD/PSB composite, SVG, PDF (any page, crop-box choice), PDF-compatible Illustrator files detected as PDF, EPS (TIFF preview or placeholder — no PostScript interpreter) (
crates/images/src/lib.rs). - Text:
.txt/.text(UTF-8 or UTF-16),.md,.docx,.rtf,.xlsx(first used range becomes a table), Tagged Text; Data Merge sources CSV, TSV, text,.xlsx. - Media (poster/placeholder frames, no playback): mp4, m4v, mov, webm, ogv, mp3, m4a, wav, ogg, oga, aac.
- Swatches
.ase, ICC.icc/.icm, XML (with DTD), libraries.dclib, books.dcbook, and a page of an IDML or.designcraftdocument (file.place {layoutPage}) as a group of objects. file.openRecent {index}backs File › Open Recent (at mostrecentFilesMax, default 20).
Native format — implemented (format version 4)
.designcraft is a zip (crates/format/src/lib.rs): mimetype (stored, first), document.json (pretty JSON), assets/ entries (byte-for-byte, each file once), meta.json (format version and generator) and an optional preview.png. Latest reader capability is version 4: version 4 covers retained placed-graphic layer options and explicit all-on placed-PDF layer choices. required_version pins a file to 4 only when it needs one of those, else keeps 2 or 3 so older readers still open it. Readers upgrade older versions and still open the legacy single-JSON form. Read limits: 100 000 entries, 256 MiB document.json, 1 GiB per asset, 4 GiB total; a document with non-finite geometry cannot be saved. Writes are atomic.
Export — implemented
- PDF (
file.exportPdf): real selectable text with embedded font subsets, DeviceCMYK/RGB/Gray, spot/Separation, bleed boxes, crop/bleed marks and page info, pages or spreads,standard: "none" | "x4" | "x1a" | "a2b"(PDF/X-1a:2003 is new this release — the PDF/X-4 print file flattened by craft-prepress, with overprint/knockout and CMYK blending preserved through the flattener), tagged structure tree, transparency flattening, hyperlink annotations and outlines, interactive options,created(Unix seconds) for reproducible files,file.printBookletimposition. PDF export now writes the File Info title, author, description and keywords (file.info, PR #1712); the composition cache is consulted once per story and page. - PDF/X-4 checks:
designcraft-cli validate-pdf FILE.pdfprints{valid, issues}and exits non-zero on failure; checks include PDF version, output intent, Info/XMP identification, interpolation, encryption, trim boxes, Type 3 fonts, device RGB under a CMYK output intent, and fonts that draw visible text without an embedded font program (including inside placed PDF forms), with font names and pages; render-mode-3 invisible text is exempt (crates/pdf/src/pdfx.rs,crates/pdf/src/pdfx/fonts.rs). - Inks and separations (new): the document's inks are a
craft_prepress::InkSet(four process inks plus each spot swatch;crates/pdf/src/inks.rs); Separations Preview shows the exported PDF's plates, spot plates included (ink.separations; the UI thread separates one sheet per frame). - EPUB 3 reflowable (
file.exportEpub) and fixed layout (file.exportFixedEpub). Split Document:document.epubSplit {split?}stores off / before each export-tagged paragraph / before each paragraph of one style;file.exportEpub {split}overrides it for one export andstyle.exportTag {split}marks the styles; navigation and note links point across the files. - HTML (
file.exportHtml): one self-contained page, styles as CSS, images embedded, stories and graphics in reading order; returnswarnings. - PowerPoint (
file.exportPptx): every page becomes a slide of editable shapes, pictures, tables and text boxes;lineBreaks: keep|reflow,rasterize(default true),embedFonts(default true); approximations reported inwarnings. - PNG / JPEG of a page via the renderer (
designcraft-cli run --export out.png,--all-pages DIR; MCPrender_page/export_png; controlui.render). - IDML (
file.exportIdml,embedImages), Text.txt/.rtf/tagged (file.exportText), XML (file.exportXml). - Print (
file.print,file.printers,dryRun,created) through the sharedcraft-printspooler —docs/gaps.md§10.
Automation surfaces — implemented
- CLI
designcraft-cli(apps/designcraft-cli/src/main.rs):run,commands [FILTER],describe COMMAND,script,app,mcp,perf,bench,validate-pdf,links,--version— 10 subcommands, unchanged at this tag. On macOS it is not insideDesignCraft.app: the release ships a separatedesigncraft-cli-<version>-macos-universal.zip.mcptakes--automation-read-root/--automation-write-rootmore than once, in--flag DIRand--flag=DIRspellings; a non-UTF-8 MCP line now answers a parse error instead of dying. - MCP server
designcraft-cli mcp— stdio JSON-RPC, protocol 2025-06-18 (older revisions accepted), 26 tools, byte-identical set to v0.13.0: command discovery/execution (list_commands,execute,batch), document I/O and inspection (inspect_document,get_story,set_story_text,new_document,open_document,save_document,place_image), rendering (render_page,export_png,screenshot), input/UI tools (select_tool,pointer,key,type_text,ime,click,drag,menu_list,ui_inspect,ui_set,dialog_set/confirm/cancel). Read/write root flags confine every path a command touches. - Control channel:
designcraft --control PORTserves JSON lines on127.0.0.1only — the dispatch gainedui.docking(shared dock layout) this release; 4 MiB line limit, 16 connections, no authentication (docs/control-protocol.md). - Scripts: one command per line with
$N.pathreferences to earlier results (crates/engine/src/script.rs;script.run {text}). The Scripts panel runs a script as one undo step and restores the document on failure. - Shortcuts on the shared craft-keymap crate (new): panel shortcuts and editable tool keys, the shared Keyboard Shortcuts dialog with shortcut sets (
window.shortcutSets), and InDesign shortcut import (window.importShortcuts {path | text}) which reads an InDesign Show Set.txt(UTF-8/BOM or UTF-16; ≤ 8 MiB), applies its Default context, and reports{set, imported, changed, conflictsCleared, skipped, unmatched, unmatchedWithoutShortcut, unreadable}(crates/ui-egui/src/shortcut_import.rs,crates/ui-egui/src/menus/keys.rs). - Surface size at this tag: 542 engine command specs (unique
cmd!ids across thespecs()lists wired intocommand_specs(), tests excluded) and 176 UI commands. Versus v0.13.0 (537 + 172): +5 engine —file.info,ink.separations,note.split,text.deleteSurrounding, plus one const-built id — and +4 UI —help.checkForUpdates,ui.dock,view.storyEditorDepthRuler,window.shortcutSets; nothing removed. MCP stays 26 and the CLI subcommands are unchanged. Discover the live list withdesigncraft-cli commandsanddescribe.
Platforms — implemented
- macOS, Windows, Linux native (
apps/designcraft); WebAssembly web build via trunk (apps/designcraft-web: WebGPU with a WebGL2 fallback,?webglto force it,?samplefor the sample magazine). The web build has no control channel, and Save/Export download files instead of writing them. Runtime environment variables:RUST_LOG,WGPU_BACKEND,WGPU_POWER_PREF,WGPU_ADAPTER_NAME,WGPU_VALIDATION_INDIRECT_CALL,DESIGNCRAFT_CONTROL_PORT,DESIGNCRAFT_CONFIG_DIR,DESIGNCRAFT_NO_PREFS,DESIGNCRAFT_NO_NATIVE_MENU,DESIGNCRAFT_WAYLAND(Linux). Windows installs per-user by default now.
Known limitations and not-implemented
Ranked shortfall list: docs/gaps.md (kept current by the maintainers — read it before promising work). Headline items at this tag:
- Pre-alpha. The alpha gate is blocked by Smart Text Reflow on the Primary Text Frame adding pages users cannot delete (#165). Threading by hand and autoflow fill-the-following-pages-first work.
- Basic canvas editing still fails for some users — object copy/paste on Windows and Linux, right-click context menus, formatting at a caret discarded (
docs/gaps.md§1). - Placed graphic layer options are retained, not rendered. IDML per-placement layer visibility is preserved and warns on import/preflight/PDF export, but the renderer and PDF exporter still use the asset's composite/default appearance; layer-comp choices and a layer-options UI are missing. Placed PDF layer choices are applied — do not generalise that to IDML/PSD layer options.
- INDD/INDT opening is unmeasured on real files; INDB/INDL are not read; no QuarkXPress import. IDML round-trip is not proven on real files — opened IDML can reflow.
- EPS is preview-only — no PostScript interpreter. No ExtendScript/UXP compatibility: InDesign scripts do not run; the script language is DesignCraft's own command language. No plug-in model. No in-app media playback.
- PDF standards: PDF/X-1a:2003 joined PDF/X-4 and PDF/A-2b this release, but there is still no PDF/X-3, PDF/UA validation, Adobe
.joboptionspresets, or output-intent choice beyond the built-in profile; PostScript printing is absent. Placed-PDF font repair is missing (gap 28): export andvalidate-pdfdetect and name visible unembedded fonts, but nothing embeds, substitutes or outlines them automatically. - HTML export is one basic page; fixed-layout EPUB writes page images rather than live text and CSS; neither output has animation or timing (gap 17).
- Hyphenation for English, Spanish, Portuguese, Norwegian and Greek only; spelling English only (gap 13). No screen-reader exposure; PDF/UA unverified (gap 25).
- Startup crashes and blank canvases on some GPU/driver combinations remain a partly mitigated class (backend fallback +
gpu.jsonskip list; gap 5). Performance: no incremental composition and no GPU raster — the canvas is CPU-rendered withvello_cpu, the GPU only composites the UI (gap 20). - Font discovery still misses fonts that some services/managers activate; disk changes are noticed only on request (
font.reload) (gap 6). Localization is partial: Japanese 95%, Czech/Polish 99%, Georgian 100%, several 61–85%, Hindi/Indonesian/Korean/Vietnamese absent (ROADMAP.md§Languages). A missing string shows English and fails no check. - Shortcut limits: the InDesign importer reads only Show Set
.txt(not.indk), applies only the Default context (Text for type/text commands), and rejects macOS Control-key chords; editing tool keys and managing sets happens in the Keyboard Shortcuts dialog, not the importer (crates/ui-egui/src/shortcut_import.rs,menus/keys.rs). - Custom column guides are horizontal column gutters only; locked by default and
layout.moveColumnGuiderefuses while locked; changing column count or gutter discards the custom positions; a page that changes side of the spine mirrors them. file.closeis not a safe "close tab": it closes without asking and discards the document's recovery data. The UI's File ▸ Close / tab × asks when the document is dirty;app.quitasks per dirty document, while the control methodapp.quitquits without asking.- Claimed but unverified: README says "every menu item, tool gesture, panel control and dialog" can be driven over the control channel and MCP. The command registry and control methods are broad, but this audit did not launch the GUI; treat a specific dialog as unverified until
ui.dialog.open/ui_inspectconfirms it. - Stale documentation to distrust:
ROADMAP.mdanddocs/target-app-parity.mdstill quote old command counts (~200 / 446+99);docs/agents.mdand the CLI'sSCRIPT_HELPsay most commands ignore unknown parameters, while the CLI, MCP and control channel reject them. Verify withdesigncraft-cli describeagainst your build.
How to operate
Launch on macOS
- GUI:
open -a DesignCraft(installed under/Applications/DesignCraft.app,CFBundleIdentifier ai.storyteller.designcraft); to open a file:open -a DesignCraft brochure.designcraft. The binary inside the bundle is/Applications/DesignCraft.app/Contents/MacOS/DesignCraft. - Real flags of the desktop binary (
apps/designcraft/src/main.rs):--sample,--control <port>(alsoDESIGNCRAFT_CONTROL_PORT),--version,--gpu-skip=<list>(internal restart bookkeeping), plus any number of file paths. - The CLI is not inside the
.app. Get it from the separatedesigncraft-cli-<version>-macos-universal.ziprelease asset,cargo install --path apps/designcraft-cli --locked, orcargo build --release -p designcraft-cli. - State lives in the app's settings folder (
~/Library/Application Support/DesignCraft/on macOS):ui.json,prefs.json,logs/designcraft.log(rotates, 16 MiB cap),gpu.json, andRecovery/.portable.txtnext to the app switches to aDesignCraftDatafolder;DESIGNCRAFT_CONFIG_DIRoverrides both.
CLI reference (exact, from apps/designcraft-cli/src/main.rs)
designcraft-cli run [--in FILE(.designcraft|.idml|.indd|.indt) | --sample] [--cmd ID[=JSON]]... [--page N] [--scale S] [--pdf-options JSON] [--export OUT] [--all-pages DIR] designcraft-cli commands [FILTER] # engine commands as JSON; FILTER matches id/label/menu designcraft-cli describe COMMAND # label, menu path, shortcut and parameters of one command designcraft-cli script [FILE|-] [--in FILE | --sample] [--connect PORT] [--save OUT] [--export OUT] [--keep-going] [--help] designcraft-cli app [--port PORT] COMMAND [JSON] | app --method METHOD [JSON] designcraft-cli mcp [--connect PORT] [--sample] [--automation-read-root DIR]... [--automation-write-root DIR]... designcraft-cli perf [--pages N] [--frames N] [--chars N] [--images N] [--runs N] [--strict] designcraft-cli bench FILE [--runs N] designcraft-cli validate-pdf FILE.pdf | links | --version
--page,--scaleand--pdf-optionsapply to the--exports that follow them; one left after the last export is an error.--exportpicks the writer from the extension:.png/.jpg/.jpeg(a page),.pdf,.designcraft(Save As),.idml,.epub,.pptx,.html/.htm,.rtf/.txt; an unknown extension is an error and nothing runs; a name with no extension is a PNG of the page.run --cmd ID=JSONuses$N.path/$last.pathreferences; a params key the command's description doesn't name is an error (checked by the CLI, MCP and control channel).scriptprints{"completed": n, "results": [...]}plusfailedIndex/failedCommand/errorand exits non-zero on failure;--keep-goingrecords failures as results instead.mcproots may each be repeated; a path inside any root of its kind passes. A root left out grants none of that access, and roots plus--connectis an error.
Document and window model
- Several documents open in tabs; each tab is its own
DocStatewith its own undo history, selection and (optionally) its ownDocument Fontsscope. A document is spreads → pages → items; text lives in stories threaded through text frames; parent pages contribute items behind a page's own. - Coordinates are points (1/72 in), y down, in spread space: on a facing spread the right page starts at
x = page width. Text offsets are UTF-8 byte offsets, not character counts (docs/mcp.md§Text offsets). - Commands that create items take
spread: an integer, or{"kind":"parent","index":N}.pagein guide/column commands is the page's index within its spread;document.inspectpageindexis absolute. - Closing:
file.close {index?}closes without prompting and discards recovery data; the UI's File ▸ Close / tab × andapp.quitask when dirty; the controlapp.quitdoes not. Save first.
Recipes for the v0.14 surfaces
sh# Explicitly show every layer of the selected placed PDF, then read the state back designcraft-cli run --in brochure.designcraft \ --cmd 'object.layerOptions={"useDefaults":false}' \ --cmd 'object.pdfLayers={}' # Split a reflowable EPUB before paragraphs of one style, for this export only designcraft-cli run --in brochure.designcraft \ --cmd 'document.epubSplit={"split":{"style":"Heading 1"}}' \ --export book.epub # Press-ready PDF/X-1a (flattened), then validate it designcraft-cli run --in brochure.designcraft \ --cmd 'file.info={"title":"Brochure","author":"A. Designer","keywords":"print"}' \ --export press.pdf designcraft-cli validate-pdf press.pdf # Story-wide hanging punctuation, then a list and a variable converted to text designcraft-cli run --in brochure.designcraft \ --cmd 'story.options={"opticalMargin":true,"opticalMarginSize":12}' \ --cmd 'list.bullets={"on":true}' \ --cmd 'variables.convertAllToText={"name":"Running Header"}' \ --export page.pdf
object.layerOptionsreturns{hidden, useDefaults};useDefaultscannot be combined with a non-emptyhidden. Readobject.pdfLayers— itsoverriddenflag separates a per-placement choice from the file's defaults.document.epubSplitwith nosplitis a query;off,"exportTags"or{"style": name}sets it. After export, unzip the EPUB and countOEBPS/content*.xhtml.story.optionsalso acceptsstory/frame; omit both to use the selection. Per-paragraphignoreOpticalMarginopts a paragraph out.selection.key {id}thenobject.align {edge, to?}— with a key object set,todefaults tokeyObject.list.bullets/list.numbersare toggles: with noonthey turn off when every selected paragraph already has the list, else on.file.infosets the document's title/author/description/keywords (File Info dialog); PDF export writes them into the PDF's Info dictionary.
Open / save / export flows
- Open:
File ▸ Open…(Cmd+O,file.open {path}) — content-sniffed;.idmland.indd/.indtroute through the IDML interchange module.file.recentFiles/file.openRecentback Open Recent. - Save:
File ▸ Save(Cmd+S,file.save) andSave As…(Cmd+Shift+S,file.saveAs {path}) write the native.designcraftpackage;file.saveACopywrites a copy without changing the open document; writes are atomic. - Recovery: unsaved documents are written to the recovery folder every 30 s by default (
recoveryMinutes, minimum 5 s) and reopened after a crash (crates/engine/src/recovery.rs;file.recovery.{save,list,open},file.revert). - Export: the
file.export*commands above, or the CLI's--export. Every export returns{path, bytes, …}plus awarningsarray where applicable — read it. - Package:
File ▸ Package(app.packageDialog,Cmd+Alt+Shift+P;file.package {dir, idml?, pdf?, instructions?}) relinks to aLinksfolder with package-relative link paths, copies placed files and document fonts, writes an IDML copy and a report.
Verified end-to-end examples
sh# Headless: build a page and export it three ways (--scale applies to the exports after it) designcraft-cli run --sample \ --cmd 'frame.create={"rect":[36,36,540,300],"content":"text","text":"Hello"}' \ --export page.png --scale 2 --export page@2x.png --export page.pdf # Discover then call a command (never guess params) designcraft-cli commands note && designcraft-cli describe note.split # Drive a running app (start it with a control port first) designcraft --sample --control 7979 & designcraft-cli app document.inspect designcraft-cli app --method ui.render '{"page":0,"scale":2}'
MCP registration (docs/mcp.md):
shclaude mcp add designcraft -- designcraft-cli mcp \ --automation-read-root "$PWD" --automation-write-root "$PWD/out"
Working with an AI agent
Legitimate and productive
- Prepare inputs. Convert to formats
crates/imagesreads (PNG, JPEG, GIF, WebP, TIFF, BMP, PSD composite), author SVG or single-page PDF for vector/print art, write.docx/.rtf/.txt/.md(UTF-8 or UTF-16) for copy, and CSV/TSV/XLSX for Data Merge. Generate a test document withfile.newSample. - Drive it through commands, not pixels. Prefer
designcraft-cli run --cmd,scriptwith$N.pathwiring, MCPbatch, or the control channel. Gesture paths exist (ui.pointer,key,text,ime,dialog_*), but commands are deterministic and return JSON. - Look at the result.
render_page/export_png/ui.renderreturn or write PNGs — read the image after layout work;ui.screenshotgives the whole window. - Inspect programmatically.
document.inspect(pages incl.columnRects/customColumns, items, stories withoverset, styles, swatches, selection incl.guides),story.get,links.list,font.list,preflight.run {minPpi?},document.preferences; view state is UI-only (ui.inspect).designcraft-cli describegives exact parameter names. - Set up geometry programmatically.
guide.add/guide.move/guide.moveBy, read back withguide.list; move column gutters withlayout.moveColumnGuideafterview.lockColumnGuides {on:false}, then verifycolumnRects. - Type work.
story.optionsfor story-wide hanging punctuation,list.bullets/list.numbersfor list buttons,note.*(incl.note.split) for notes,variables.convertToTextwhen a client wants the running headers flattened,style.exportTag/document.epubSplitbefore an EPUB deliverable. - Repair and analyse native files. A
.designcraftis a zip: unzip, readdocument.json,meta.jsonandassets/. Re-zipping by hand is risky: the reader requiresdocument.json, honoursmeta.json's version (above 4 is refused), and runsDocument::check()plus asset wiring on load. Prefer open → re-save through a command. - Verify exports.
designcraft-cli validate-pdf out.pdf,preflight.run,story.getfor overset text,links.listfor missing images, every export'swarnings, and an EPUB content-file count afterdocument.epubSplit. - Work on throwaway copies. Copy the project file before a session; isolate a run with
DESIGNCRAFT_CONFIG_DIRpointed at a scratch folder.
Do not attempt
- Do not assume parity: check
docs/gaps.mdanddesigncraft-cli describe. ExtendScript, UXP,.joboptionspresets, plug-ins and Adobe cloud features do not exist (gaps 9, 22, 23). - Do not promise layer-aware output for IDML/PSD layer options: only placed-PDF layer choices render and export; retained IDML graphic-layer settings warn instead.
- Do not promise PDF font repair: unembedded fonts in placed PDFs are detected and named, not fixed (gap 28).
- Do not assume the CLI or MCP server is installed: on macOS the
.appholds only the desktop app. Build or download it first, and say so. - Do not run
file.closeor the control methodapp.quiton a dirty document — both discard unsaved work and recovery data. Theapp.quitcommand (and the UI) asks first. - Do not expect the shortcut importer to read
.indk, apply non-Default contexts, or handle macOS Control-key chords; checkchangedand test a shortcut after importing. - Do not move column guides on a locked document; unlock first and re-lock. Do not interpret EPS/PostScript or expect
.indd/.indtfidelity, INDB/INDL, or QuarkXPress import. - Do not drive the GUI blind (no screenshot/inspect feedback), and never run
--controlon a port you do not control: the channel has no authentication (docs/control-protocol.md).
Verification protocol
DesignCraft is pre-alpha: treat every export as unverified until you have looked at it.
- Throwaway round-trip first. New document (
file.newor--sample) → one edit → save a.designcraft→ reopen it (--in) → export the same page to PNG and PDF → check the PNG visually and the PDF withvalidate-pdfif you asked forstandard: "x4"or"x1a". If a step fails or geometry moved, stop and report. - Never trust a silent export. Read the JSON result (
bytes,pages,slides,warnings) and confirm the file exists and is non-empty. A failed step in a non---keep-goingscript still leaves earlier steps applied in the live app: re-inspect before retrying. - Version and back up per session. The format version is in
meta.json; version 4 documents are refused by older readers. Keep a copy at the start of a session; to deliver files to someone on an older build, test one round-trip on their version first. - Update between projects, not during one. After a launcher update, re-verify the bundle version and build commit (
plutil -p /Applications/DesignCraft.app/Contents/Info.plist | grep -E 'Version|BuildCommit'; at this pin: 0.15.2, commit7e70203…). - Isolate test runs.
DESIGNCRAFT_CONFIG_DIRto a scratch folder,DESIGNCRAFT_NO_PREFSto avoid writing preferences, and--automation-read-root/--automation-write-root(repeatable) for MCP. - Prefer re-opening over re-editing. The reader upgrades and validates on load, so save → reopen is the cheapest proof that an edit produced a valid document.
- Verify geometry, not just "no error". After guide edits read
guide.list; afterlayout.moveColumnGuidereaddocument.inspect'scolumnRects/customColumns. Reopen and confirm they survive (and IDML too, if handing off IDML). - Verify the typographic and EPUB settings. After
story.optionsre-readtype.selectionAttrs.storyOptions; afterdocument.epubSplitunzip the EPUB and count content files, and click one cross-file link target. - Verify a placed-PDF choice in the output. Export PDF, then check the exported file's optional content (or the warnings) — a choice that could not be applied is an error, and external-only IDML export refuses active choices.
Verify against your installed version. The repository at this pin and the installed bundle match exactly; if the launcher has since updated DesignCraft, re-run step 4 and re-check command parameters with designcraft-cli describe before relying on them.
Sources & evidence
- Repository: https://github.com/storytold/designcraft — inspected at tag v0.16.0, commit
1fe8885bda7451263879cfbb256b9a3d46c411bf(git rev-parse HEAD; "Release 0.16.0", 2026-11-01), audited 2026-11-02. The v0.15.2 ref was fetched for set diffs; the registry (engine commands, UI commands, 26 MCP tools, control methods, 10 CLI subcommands, format version) is unchanged between the two tags. - Installed app:
DesignCraft.appin the system Applications folder; the binary printsdesigncraft 0.16.0(Contents/Info.plistinspected, never launched). The bundle contains onlyDesignCraft; nodesigncraft-cliis installed on the audit machine. - Read for this skill:
README.md,Cargo.toml,ROADMAP.md,AGENTS.md,docs/{agents,mcp,control-protocol,gaps,target-app-parity,file-format-parity,graphic-layer-options}.md,apps/designcraft/src/{main,profile,control_server}.rs,apps/designcraft-cli/src/{main,automation_args}.rs,crates/format/src/lib.rs,crates/engine/src/{lib,script,recovery,io,file_access}.rs,crates/engine/src/cmd.rsandcrates/engine/src/cmd/(incl.export.rs,pdflayers.rs,text.rs,variables.rs,lists.rs,editorial.rs,edit.rs,object.rs,file.rs,guides.rs,layout.rs,params.rs,package.rs),crates/mcp/src/{tools,server,headless,backend}.rs,crates/ui-egui/src/{control,shortcut_import,page_history,story_editor}.rs,crates/ui-egui/src/menus/{ui_commands,keys,bar}.rs,crates/doc/src/{page,item,assets}.rs,crates/compose/src/,crates/pdf/src/{lib,pdfx,pdfx/fonts,inks,optional_content}.rs,crates/epub/src/lib.rs,crates/idml/src/{import,export}.rs,crates/images/src/lib.rs,crates/textimport/src/lib.rs. - Counts carried from the v0.14.0 audit (
cmd!ids viagit grepbetween tags;UI_COMMANDSid sets diffed between tags) and re-diffed unchanged for v0.15.2 and v0.16.0: 542 engine / 176 UI / 26 MCP tools / control methods +ui.docking/ 10 CLI subcommands / format version 4. Live discovery beats this document:designcraft-cli commands,designcraft-cli describe ID, anddocs/gaps.md. - Deep automation tables (CLI, scripts, MCP tools, control methods, coordinates, guides/columns, layer options, EPUB split, story options, shortcut import, sample commands):
references/agent-surfaces.md.


