Assemblash
FreeNot checkedLocal-first visual document engine with a web editor, CLI, API, and MCP server - built for humans and AI agents.
About
Local-first visual document engine with a web editor, CLI, API, and MCP server - built for humans and AI agents.
README
Assemblash
A local-first visual document engine for people, applications, scripts, and AI agents.
Assemblash creates structured visual documents from text, images, SVGs, groups, templates, and reusable styles. The result stays editable: you can inspect the layer tree, apply a typed operation, undo it, render a preview, and export PNG or SVG without depending on a cloud service.
It ships as one small executable with a browser-based editor, a command-line interface, a local HTTP API, an embedded Rust API, and an MCP server. Every interface goes through the same validated operation layer, so a change made by an agent behaves like a change made by a person.
Current release: 1.6.0. The document schema and operation API have been stable since 1.0. See the release notes or changelog for the full history.
Created as a structured Assemblash document and exported by the deterministic renderer. Inspect the editable project.
Why Assemblash?
Visual work usually lands at one of two extremes: a powerful editor that is hard to automate reliably, or a code/generation pipeline that produces a flat image nobody can comfortably refine. Assemblash sits in the middle.
- Structured, not flattened. Documents keep their layers, groups, assets, metadata, templates, and named slots.
- Local by default. Creating, editing, rendering, and exporting work offline. No account or AI provider is required.
- Safe to automate. Mutations are typed, validated, journalled, versioned, dry-runnable, and undoable. Protected content stays protected.
- Deterministic. The same document, assets, and pinned font files produce bit-identical PNGs on all six supported release targets.
- Easy to embed. Use the Rust crates, HTTP API, CLI, or MCP server instead of driving the reference interface with clicks.
The AI story is deliberately small, and it is the whole story: an MCP server and an attributed history. An agent connects over MCP and brings its own model. No provider adapter ships with Assemblash, and the core never requires one — a document is created, edited, rendered, and exported with no model involved at all. What an agent does goes through the same validated operation layer as a click or a shell command and lands in the journal with its actor, so its work is reviewable and undoable rather than merely trusted.
Assemblash is deliberately not a Photoshop, GIMP, or Figma replacement. It is a focused composition engine for repeatable visual assets, templates, and agent-assisted workflows.
Get started
Download a release
Pick the download that fits your machine from GitHub Releases:
| Platform | Download | Run it |
|---|---|---|
| Windows | assemblash-<version>-windows-<arch>.exe |
Double-click it. |
| Debian, Ubuntu | assemblash_<version>_<arch>.deb |
sudo apt install ./assemblash_<version>_<arch>.deb, then pick Assemblash from the application menu. |
| macOS | the .tar.gz archive |
Unpack it, then see the note below before first launch. |
| Anything else | the .zip or .tar.gz archive |
Unpack it and launch assemblash. |
The executable is self-contained — the editor is compiled into it — so the
single file is the whole program. The archives and the .deb additionally
carry the licence texts and the changelog.
Launching it without arguments creates a local workspace, starts the server, and opens the editor in your browser. A second launch opens the server that is already running. You can stop it from the editor.
The macOS binaries are not signed with an Apple Developer ID, so macOS quarantines them on download and Gatekeeper refuses the first launch. Clear the flag yourself after unpacking:
xattr -d com.apple.quarantine ./assemblash
A Homebrew tap would remove that step, since Homebrew clears the flag on what
it installs. The formula is written and lives in packaging/homebrew/, but
the tap is not published yet, so there is no brew install to run today.
Install from source
Building requires Rust 1.92 or newer:
cargo install --git https://github.com/VidGuiCode/assemblash --tag v1.6.0 assemblash-cli
Create and export from the CLI
Assemblash never substitutes a system font behind your back. Install a font into a local store once, then use that same store when exporting:
assemblash font install "Noto Sans" --font-store ./assemblash-fonts
assemblash new ./poster --width 800 --height 400 --background '#f6f4ef'
assemblash add-text ./poster --text "Hello" --font "Noto Sans" --size 64 --x 40 --y 40 --width 720 --height 120
assemblash add-rect ./poster --x 40 --y 200 --width 240 --height 96 --fill '#1d1d1f' --corner-radius 12
assemblash export ./poster --out poster.png --font-store ./assemblash-fonts
Already have a font file? Use --font /path/to/SomeFont.ttf or
--font-dir /path/to/fonts instead. Run assemblash --help or
assemblash <command> --help for the complete command reference.
add-ellipse and add-line take the same box flags; a line's box is the line,
so --width is its length and --rotation its angle.
The editor manages the same store without a terminal. Its Add panel has a
Fonts section (1.5.0 and newer) that lists the installed families and their
faces, imports TTF, OTF, TTC, OTC, WOFF and WOFF2 files from disk, and removes
a family after confirming that projects using it will report a missing font
until it is imported again. When the store is empty it offers a single button
that installs the bundled default pack — Noto Sans, Noto Serif and Noto Sans
Mono — naming what it will download before anything is fetched. The font picker
and the canvas update immediately, and removing a family never touches your
operating system's fonts or the file you imported from.
To change a layer afterwards, assemblash set reaches every updatable
property — name, position, size, rotation, opacity, visibility, lock, blend
mode, effect stack, text, font, size, colour, alignment, line height, fill,
stroke, stroke width, corner radius, fit, and asset:
assemblash set ./poster --layer <LAYER_ID> --color '#1d1d1f' --size 72 --line-height 1.4
However many flags you give it, one invocation is one operation: journalled once, undone once.
render and export take the output path positionally as well as through
--out, and both print the written path and its sha256: digest as one
tab-separated line, so a script can compare what two interfaces produced
without hashing the file itself:
assemblash export ./poster poster.png --font-store ./assemblash-fonts
Platform compatibility
The same six platforms are built, tested, and included in every release:
| Operating system | x86_64 / Intel / AMD64 | ARM64 / AArch64 |
|---|---|---|
| Windows | ✅ .exe, .zip |
✅ .exe, .zip |
| Linux | ✅ .deb, .tar.gz |
✅ .deb, .tar.gz |
| macOS | ✅ Intel .tar.gz |
✅ Apple silicon .tar.gz |
Every release carries a bare .exe per Windows target and a .deb per Linux
target beside the archives. macOS has no installer of its own yet — see the
note above about the quarantine flag.
The release workflow checks that every binary starts before attaching it. CI also runs the Rust workspace tests on all six targets. The reference editor runs in a modern browser and is served by the executable itself.
What is included
A structured document engine
- Canvas dimensions and background settings
- Text, raster image, SVG, shape, and nested group layers
- Rectangle, ellipse, and line shapes with fill, stroke, and corner radius
- Position, size, rotation, scale, opacity, visibility, and ordering
- Stable IDs, metadata, locking, duplication, grouping, and ungrouping
- Alignment, centering, distribution, snapping, bounds, and overlap queries
- JSON persistence with unknown-field preservation
- Named presets, templates, slots, and deterministic variant batches
A project remains ordinary, portable files:
my-project/
├── document.json
├── assets/
└── history/
You can inspect and hand-edit document.json. Normal edits should still go
through an Assemblash interface so they are validated and recorded in history.
The published contracts live in schema/.
Rendering and export
Assemblash converts a document to SVG as a pure function and rasterizes it with
resvg and tiny-skia. It supports PNG export, compatible SVG export,
configurable output dimensions, fourteen deterministic blend modes, and a
non-destructive effect stack for brightness, contrast, saturation, blur,
seeded grain, and drop shadow — a glow being that shadow with no offset.
Fonts are loaded only from files you explicitly provide or install into the font store. Their bytes are hashed and pinned, which keeps typography and export pixels consistent across operating systems.
An export also reports what it could not do well. It produces
wordBrokenMidWord when a single word is too wide for its box and has to be
split, textOverflowsBox when laid-out text is taller than the box holding it,
and — from 1.5.0, on the HTTP and MCP paths only — lockReclaimed when the
server reclaimed a stale project lock before producing it. Each carries a
code, a message, and the layerId
where one applies. A warning is advisory: it changes no pixel and no exit
status. The HTTP export response and the MCP export_document result carry a
warnings array; the CLI prints one line per warning on stderr, or the whole
array as JSON on stdout with --warnings-json.
Text inside an imported SVG asset is not advisory. From 1.5.0 a render refuses,
with a typed error naming the asset, unless every <text> in that asset names
at least one non-generic font family the render loaded; text that names only a
generic family such as sans-serif is refused too, because the pinned store
never holds the renderer's fallback. Earlier releases exported such a document
successfully with the text simply absent, which looked finished and was not.
Name a loaded family in the asset, or outline the text before importing it. The
1.3.0 warning code svgAssetTextWithoutFont is kept but is no longer produced
for this case, because the refusal comes first.
History and safety
Every mutation uses the same transactional operation layer. A refused operation leaves the document unchanged. Successful operations are journalled with their actor and transaction ID and can be undone or redone across restarts.
- Expected-version checks prevent stale clients from overwriting newer work.
- Dry run shows what a supported mutation would do without committing it.
locked,protected, andreadOnlylayers are enforced in the engine, not just hidden behind UI controls.- Project and asset paths stay inside the configured filesystem boundary.
- Imported SVGs are sanitized before they enter the asset store.
Choose the interface that fits
| Interface | Best for | Start with |
|---|---|---|
| Reference editor | Creating and refining documents visually | Launch assemblash |
| CLI | Shell scripts and straightforward local workflows | assemblash --help |
| HTTP API | Applications and custom frontends | assemblash serve |
| MCP server | AI agents and MCP-compatible clients | assemblash mcp |
| Rust crates | Embedding the engine directly | crates/ |
The editor is a reference client, not a privileged implementation. Its edits, the CLI, HTTP requests, and MCP tools all compile to the same operations.
Most MCP clients can start Assemblash with this configuration:
{
"command": "assemblash",
"args": ["mcp"]
}
Add --project /path/to/project to expose one project instead of the workspace.
The MCP server provides read tools for documents, layers, validation, history,
and rendered previews, plus mutation tools with dry run, version checks,
protection checks, and undo transaction IDs.
An agent can also start a project with create_project, add a layer drawing an
already-imported SVG asset with add_svg_layer, ask for the document's vector
render as text with render_document, and query overlapping layers with
find_overlaps — the same pairs, in the same order, that the CLI and the HTTP
API report. update_layer sets lineHeight beside the other text properties,
and export_document returns the same warnings array the other interfaces
report.
For agents working from a repository checkout, a reusable public skill is in skills/assemblash/SKILL.md. It explains the document-first workflow and the guarantees an integration must preserve.
How the pieces fit together
Reference editor ───────┐
CLI and scripts ────────┼──> API / typed operations ──> document + history
Custom applications ───┤ │
AI agents via MCP ──────┘ └──────────────> renderer + export
The API and MCP server do not contain their own document logic. They are
adapters over assemblash-core, which owns validation and operations;
assemblash-renderer owns rendering; and the server, MCP, and CLI crates expose
those capabilities to different clients.
The implementation is Rust with a TypeScript reference interface. The
executable embeds the built interface, so users do not need Node.js. The
official scratch container image is about 9 MB.
Local use and self-hosting
assemblash serve listens on 127.0.0.1 by default and needs no configuration:
assemblash serve
A non-loopback bind refuses to start without an access token:
assemblash token show
assemblash serve --bind 0.0.0.0
The token authenticates requests; it does not encrypt traffic. Put Assemblash behind a TLS reverse proxy when it is reachable beyond a trusted network. See DEPLOYMENT.md for Docker, Caddy, Traefik, nginx, and identity provider guidance.
If a project's lock file is left behind by a process that died, opening the
project is refused until someone clears the claim — from the editor's confirm
dialog, or with assemblash unlock. serve --reclaim-stale-locks (also
accepted by assemblash mcp, and on from 1.5.0 by the double-click or
--friendly launch, where there is nobody at a terminal) lets the server clear
such a claim on its own, but only when the lock names this machine and its
process is provably gone. A lock from another machine, or one written by an
older build that recorded no machine name, still needs a person: on a synced
project folder a process id from a different computer proves nothing. Every
reclaim is reported in the server log, in the editor, and as a lockReclaimed
export warning.
Edit the canvas
Use the Canvas button to open the editor's Properties panel. Set dimensions, choose a background or transparency, select a resize anchor, and apply the changes together. Layers keep their sizes; the anchor controls only their positions. The CLI equivalent is:
assemblash canvas set ./poster --width 1200 --height 900 --background "#102030" --anchor center
assemblash canvas set ./poster --no-background
assemblash undo ./poster
MCP exposes update_canvas with width, height, background, anchor,
expectedVersion and dryRun. HTTP accepts the same canvas fields in an
updateCanvas operation at POST /api/projects/{id}/operations. Omit
background to preserve it or send null to clear it. A resize that would
move locked, protected or read-only content is refused atomically.
Canvas editing requires 1.4.0 or newer. Once a project records
updateCanvas, 1.3.1 refuses both show and history because it cannot parse
that journal operation, even after undo. Continue using the newer binary;
do not edit the journal. The document schema remains version 1.
The Add panel's Shapes row (1.6.0 and newer) adds a rectangle, an ellipse
or a line, and a shape's inspector then edits Fill, Stroke, Stroke width and,
for a rectangle, Corner radius — each row one undoable change, with a None
button beside each paint for removing it. A drop shadow is an effect rather
than a shape property: add dropShadow to any layer's effect stack and set its
dx, dy, blur and colour, leaving both offsets at 0 for a glow.
Stability and current limits
Assemblash 1.x makes two compatibility promises:
- A document written by 1.0 remains readable by every 1.x release.
- A client written against the 1.0 operation API keeps working across 1.x.
Breaking either contract requires a major release and a documented migration. Additive fields use defaults, and unknown document fields survive load and save.
The important limits are stated plainly:
- Styled text runs are not implemented yet.
- AI image/provider adapters do not ship and are out of scope for the core.
- Fourteen blend modes are supported.
color-dodgeandcolor-burnare refused because they are not bit-identical across every target. - A document containing a shape layer needs 1.6.0 or newer: 1.0 through 1.5
refuse to read the whole document, naming
shapeas a layer kind they do not know. - A shape's stroke is painted inside its box, so the box is the visual box — except below width 1, where the stroke is drawn as a hairline centred on the edge and may spill up to half a pixel outside the box.
- Built-in authentication is one shared token. Accounts, roles, OIDC, SSO, TLS, and per-user audit identity belong in a reverse proxy.
- The editor is intentionally a reference client rather than a complete professional design application.
For the product scope and design rationale, read PRD.md. For the precise changes in each release, read CHANGELOG.md.
Try it and tell us what you find
Assemblash is released and the core contracts are stable; the useful next step is seeing it in real workflows. If you try it, the project would genuinely benefit from hearing what you made, what felt smooth, and what got in your way.
- Share a workflow, result, or question in GitHub Discussions.
- Report reproducible problems with the bug form.
- Propose a focused addition with the feature form.
Security problems are the exception: report those privately as described in SECURITY.md.
Develop and contribute
Clone the repository and run the Rust checks from its root:
cargo fmt --all --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace
The TypeScript project is inside ui/—there is intentionally no root
package.json:
cd ui
npm ci
npm run check
ui/dist/ is committed because the Rust binary embeds it. After changing the
interface, npm run build must leave that directory up to date.
Before proposing a change, please read CONTRIBUTING.md. It explains the stability rules, testing expectations, and the line between the generic engine and downstream adapters. Security problems should be reported privately as described in SECURITY.md, never as public issues.
Useful project documents:
| Document | What it covers |
|---|---|
| PRD.md | Scope, requirements, invariants, and product decisions |
| CONTRIBUTING.md | Contribution and review expectations |
| DEPLOYMENT.md | Tokens, Docker, TLS, and reverse proxies |
| SECURITY.md | Supported releases and private reporting |
| DEPENDENCIES.md | Dependency and license inventory |
| CHANGELOG.md | Release-by-release history |
Assemblash is licensed under the Apache License 2.0. The public repository contains only the generic engine and neutral examples; private brand kits, credentials, customer assets, and downstream workflows belong outside it.
Installing Assemblash
This server has no published package — it is built from source. Open the repository and follow its README.
▸ github.com/VidGuiCode/assemblashFAQ
Is Assemblash MCP free?
Yes, Assemblash MCP is free — one-click install via Unyly at no cost.
Does Assemblash need an API key?
No, Assemblash runs without API keys or environment variables.
Is Assemblash hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install Assemblash in Claude Desktop, Claude Code or Cursor?
Open Assemblash on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
LibreOffice Tools
Enables AI agents to read, write, and edit Office documents via LibreOffice with token-efficient design. Supports multiple formats including DOCX, XLSX, PPTX, a
by passerbyflutterdannote/figma-use
Full Figma control: create shapes, text, components, set styles, auto-layout, variables, export. 80+ tools.
by dannoteLogo.dev
Search and retrieve company logos by brand or domain. Customize size, format, and theme to match your design needs. Accelerate design, prototyping, and content
by NOVA-3951Design Inspiration Server
Searches top design platforms like Dribbble and Behance to provide UI inspiration, color palettes, and layout patterns via the Serper API. It allows users to re
by YonasValentinPIX4Dmatic
Enables GUI automation for controlling PIX4Dmatic on Windows through MCP. Supports launching, focusing, capturing screenshots, sending hotkeys, clicking UI elem
by jangjo123Figma
Extract design specs and assets
by Figmamcp-dockmaster
An Open-Sourced UI to install and manage MCP servers for Windows, Linux and macOS.
ariekogan/ateam-mcp
Build, validate, and deploy multi-agent AI solutions on the ADAS platform. Design skills with tools, manage solution lifecycle, and connect from any AI environm
by ariekoganthinkchainai/mcpbundles
MCP Bundles: Create custom bundles of tools and connect providers with OAuth or API keys. Use one MCP server across thousands of integrations, with programmatic
by thinkchainaiarikusi/nakkas
MCP server that turns AI into an SVG artist. One rendering engine with JSON config, AI controls all design parameters. CSS @keyframes + SMIL animations, 16+ ele
by arikusiCompare Assemblash with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All design MCPs
