Development environment
Install the mcut monorepo, run local development, and validate changes.
Prerequisites
mcut is a Bun workspace monorepo managed with Turbo.
- Use Bun
1.3.14. - Package consumers should use Node
20.11or newer. - Run commands from the repository root unless a package README says otherwise.
Install
bun installCI uses a frozen lockfile:
bun install --frozen-lockfileWorkspace layout
packages/*: publishable@mcut/*SDK packages.examples/*: runnable examples for headless editing and MCP workflows.apps/studioholds the Studio renderer, a static Next export, and the shadcn registry source.apps/desktopholds the Electron shell that serves the export and hosts the live bridge.apps/web: the marketing site and/docsimplementation.docs/: maintainer and release process notes for the repository.
Run locally
Studio in the desktop window
Run this from the repo root:
bun devbun dev builds the packages, starts next dev on port 3000, and opens the
Electron app with MCUT_DEV_URL=http://localhost:3000 so the window loads the
dev server with hot reload. The app hosts the live bridge on port 44737 and
prints its MCP_URL line, which bun dev echoes. Paste that URL into any
Streamable HTTP MCP client, or use Add to Cursor from the app's MCP menu.
Ctrl-C stops both processes.
bun dev watches apps/desktop/src and packages/desktop-ipc/src. It rebuilds
with tsdown, retypechecks apps/desktop on a contract change, and relaunches
the Electron window. A main or preload edit reaches the window without a
restart. Renderer edits still hot reload through the Next dev server.
Main runs with --inspect=9229 and the renderer with
--remote-debugging-port=9222. dist/main.mjs and dist/preload.cjs carry
source maps. .vscode/launch.json has Attach to Studio, which attaches to
both while bun dev runs.
bun run desktop:check is the one command that builds, typechecks, lints,
packages, and smokes the desktop app.
The token comes from the app's user data directory, see
Install Studio. MCUT_STUDIO_PORT
and MCUT_BRIDGE_PORT change the two ports.
Browser bridge without Electron
The standalone bridge is the developer path for a browser tab, the same process
bunx -p @mcut/mcp-server mcut-bridge start runs outside the repository:
bun run scripts/mcut-local-dev.ts bridgeIt listens on 44737 with the fixed token mcut-local-dev. Start
bun run --cwd apps/studio dev in another terminal and open the URL from
bun run scripts/mcut-local-dev.ts url. bun run scripts/mcut-local-dev.ts mcp-url
prints the matching MCP URL.
The package also exposes compatibility stdio entrypoints: mcut-mcp for
file-backed projects, mcut-mcp-live for clients that should start their own
live bridge, and mcut-bridge mcp for clients that cannot connect over HTTP.
Docs site only
bun run dev:webValidate changes
Use the narrowest command that covers your change while working, then run the broader checks before opening a pull request.
bun run build
bun run typecheck
bun run test
bun run lint
bun run smoke:packagesbun run test includes a compositor pixel test that renders in Playwright
Chromium. Install that browser once with bunx playwright install chromium.
Release validation runs the full package gate:
bun run release:checkrelease:check builds packages, typechecks, runs tests, runs package smoke
checks, and validates package metadata.
Studio smoke by surface
apps/studio/smoke drives every user-facing Studio feature the way a user
does, on three surfaces. embed is the static export the homepage serves,
opened in Chromium. electron-dev is apps/desktop/dist under the development
Electron. installed is a packaged binary such as the released AppImage or the
.app inside the DMG. features.ts is the one registry. It closes the feature
ids and the surfaces, gives each feature a tier, and marks the cells a surface
cannot offer, such as the AssemblyAI key field on the site. One driver per
feature runs on every surface and asserts a literal, so the report has one
pass, fail, blocked, or unsupported row per feature per surface, with a
screenshot for each.
bun apps/studio/smoke/coverage.ts
node --no-warnings apps/studio/smoke/run.ts --surface embed
xvfb-run --auto-servernum -- node --no-warnings apps/studio/smoke/run.ts --surface electron-dev --tier fast
xvfb-run --auto-servernum -- node --no-warnings apps/studio/smoke/run.ts --surface installed --electron release/mcut-studio.AppImagecoverage.ts prints the matrix and the cells with no driver, and fails with
--strict when a gap exists. run.ts writes report.md, report.json, and
one screenshot per feature under reports/smoke/<surface>. The runner runs
under node, because Playwright's _electron.launch hangs under Bun.
The on-device caption drivers download the Whisper model over the real network
when huggingface.co answers. When it does not, set MCUT_WHISPER_MIRROR to a
directory holding onnx-community/<model>/... and the harness serves it on
127.0.0.1 and routes the Hub and jsDelivr requests there. Without either the
row reports blocked. The Center person driver needs no network, because the
YuNet face model ships in @mcut/media, and it fails if Studio requests the
model file. ASSEMBLYAI_API_KEY turns the AssemblyAI row into a
real cloud transcription. MCUT_CHROME_PATH points the embed at Google Chrome
for MP4 export.
.github/workflows/smoke.yml runs the fast tier of electron-dev on every
pull request that touches Studio, the desktop shell, or a package, and the full
tier of every surface nightly and on workflow_dispatch. The installed jobs
download the latest mcut-desktop@* release, or the tag given as the
release input, and smoke the AppImage on Ubuntu and the arm64 DMG on
macos-15.
Website docs
The website docs are written in apps/web/content/docs. The web app generates
Fumadocs sources and static Markdown mirrors during build, and copies the
shadcn registry from apps/studio/public/r into public/r so
https://mcut.com/r/<item>.json serves the committed registry:
bun run --filter=mcut-web buildUse the web package checks when editing docs or site code:
bun run --filter=mcut-web typecheck
bun run --filter=mcut-web lint