This document is the maintainer-facing release guide for marktodocx. It covers the three hosts that ship to public registries (VS Code Marketplace, Chrome Web Store, ClawHub) and explicitly states the CLI release policy.
User-facing listing copy lives next to each host:
apps/vscode-extension/README.md— VS Code Marketplace listingapps/chrome-extension/README.md— Chrome Web Store listingapps/agent-skill/SKILL.md— ClawHub listingapps/agent-skill/INTRO.md— GitHub Release description for the agent skillapps/agent-skill/README.md— manual / developer deployment recipes
This file owns the release process, not the listing copy.
- Publishing Guide
- All hosts follow semver.
- Each host owns its own version in its own
package.json. Versions are independent — bumping the VS Code extension does not require bumping the Chrome extension. - The Chrome extension's
manifest.jsonversionfield is always synced fromapps/chrome-extension/package.jsonat build time by themarktodocx-sync-manifest-versionVite plugin. Do not editpublic/manifest.jsonversionby hand — it is treated as a placeholder (0.0.0) and overwritten indist/manifest.jsonduringnpm run build:chrome-extension. - Tag releases on
mainas<host>-v<version>(for examplevscode-extension-v0.1.0,chrome-extension-v0.1.0,agent-skill-v0.1.0). Tags drive GitHub Release artifact names. - Pushing one of those host tags triggers
.github/workflows/release-assets.yml, which creates or updates the matching GitHub Release and uploads the host artifact set for that tag. .github/workflows/release-assets.ymlalso supportsworkflow_dispatchwithrelease_tagandsource_refinputs, so you can rebuild and re-upload assets for an existing host tag from a newer branch or commit without pushing a new tag.
Before publishing any host:
- The working tree is clean and pulled to latest
main. npm installhas been run from the repo root.npm run test:parity:allis green. This runs the extension, CLI, VS Code, and agent-skill parity gates and is the canonical pre-ship gate.- The host's
package.jsonversionhas been bumped. - The CHANGELOG (or commit body) mentions what changed for this host.
If any of these fail, do not publish.
- Register a Marketplace publisher at https://marketplace.visualstudio.com/manage. The current
apps/vscode-extension/package.jsondeclares"publisher": "zhao-kun", so register the publisher IDzhao-kun. If you choose a different publisher ID, changepublisherinapps/vscode-extension/package.jsonto match before publishing. - Generate an Azure DevOps Personal Access Token with the Marketplace → Manage scope. The PAT is what
vsce loginconsumes. Treat it like a password. - Install the publisher CLI globally (or use
npx):npm install -g @vscode/vsce
- Log in once on this machine:
vsce login zhao-kun
vscewill prompt for the PAT.
-
Bump
apps/vscode-extension/package.jsonversion. -
From the repo root, build and package the VSIX:
npm install npm run package:vscode-extension
Output:
apps/vscode-extension/dist/marktodocx-vscode-extension.vsix. -
Smoke-install the VSIX locally to confirm it loads in a clean window:
code --install-extension apps/vscode-extension/dist/marktodocx-vscode-extension.vsix --force
Reload, run marktodocx: Convert Markdown to DOCX on a sample file, and confirm a
.docxis produced. -
Publish to the Marketplace:
cd apps/vscode-extension npx @vscode/vsce publish --no-dependenciesOr use the workspace script:
npm run publish:marketplace --workspace apps/vscode-extension
vsce publishreads the version frompackage.json. In this monorepo, the--no-dependenciesflag is required because the extension is already bundled intodist/. Without that flag,vscecan traverse workspace-linked dependencies and repo-root files during packaging, which leads to errors such asinvalid relative path: extension/../../publish.md. -
Confirm the listing went live at:
https://marketplace.visualstudio.com/items?itemName=zhao-kun.marktodocx-vscode-extensionThis URL will return HTTP 404 until the first successful
vsce publish. After that, every subsequent publish updates the same listing. -
Tag and push:
git tag vscode-extension-v<version> git push origin vscode-extension-v<version>
-
GitHub Actions automatically creates or updates the GitHub Release for that tag and uploads
apps/vscode-extension/dist/marktodocx-vscode-extension.vsix.
vsce packages everything in apps/vscode-extension/ except what .vscodeignore excludes. The current .vscodeignore ships dist/, media/, LICENSE, README.md, and package.json, and excludes src/, webview/, scripts/, node_modules/, vite configs, and source maps. The Marketplace listing is rendered from README.md.
- Icon:
apps/vscode-extension/media/icon.png(128×128, referenced bypackage.jsoniconfield). - Description:
package.jsondisplayNameanddescription. - Long description:
apps/vscode-extension/README.md. - README screenshots for the Marketplace should use absolute public image URLs, typically GitHub raw URLs that point at versioned files in this repository. Do not rely on relative paths such as
media/...or../../assets/...in the listing README, because the Marketplace README renderer can show those images as broken even when the VSIX contains the files. - Categories:
Formatters,Other. - Keywords: see
package.jsonkeywords— these drive Marketplace search.
If you change any of these, run npm run package:vscode-extension again so the next VSIX picks them up.
- Register at https://chrome.google.com/webstore/devconsole/ and pay the one-time $5 developer fee.
- Verify your developer email.
- Prepare and store the listing assets in a stable place (do not commit large promo images to the repo unless you want them under version control):
- Store icon: 128×128 PNG (the existing
apps/chrome-extension/public/icons/icon-128.pngworks as the source). - Screenshots: at least one 1280×800 or 640×400 PNG showing the popup with a folder selected and the convert button.
- Small promo tile: 440×280 PNG.
- Privacy policy URL: a public URL describing what the extension does and does not collect. The Privacy section in
apps/chrome-extension/README.mdis suitable; host it via the GitHub Pages of this repo or link to the README anchor on github.com.
- Store icon: 128×128 PNG (the existing
- Bump
apps/chrome-extension/package.jsonversion. Do not editpublic/manifest.jsonversion— it is overwritten at build time. - From the repo root, build the extension:
Verify
npm install npm run build:chrome-extension
apps/chrome-extension/dist/manifest.jsonversionmatchespackage.jsonafter the build. - Smoke-load
apps/chrome-extension/dist/as an unpacked extension inchrome://extensions/(Developer mode), select the test folder, and confirm a.docxis produced. - Zip the unpacked build:
cd apps/chrome-extension/dist zip -r ../marktodocx-chrome-extension.zip .
- Upload the zip to the Web Store Developer Dashboard. The dashboard path differs for the first release vs. subsequent releases:
- First release: open https://chrome.google.com/webstore/devconsole/, click Add new item, accept the developer agreement if prompted, then upload
apps/chrome-extension/marktodocx-chrome-extension.zipon the resulting screen. - Subsequent releases: open https://chrome.google.com/webstore/devconsole/, click the existing marktodocx item in the items table, then click Package → Upload new package and upload the same zip.
- First release: open https://chrome.google.com/webstore/devconsole/, click Add new item, accept the developer agreement if prompted, then upload
- Fill in the listing fields. All listed fields are required for the first release; for subsequent releases, only update the ones that changed:
- Title:
marktodocx - Summary: one-line description (matches
apps/chrome-extension/public/manifest.jsondescription) - Description: paste the body of
apps/chrome-extension/README.md - Category:
Productivity - Language: English
- Store icon:
apps/chrome-extension/public/icons/icon-128.png - Screenshots: at least one 1280×800 or 640×400 PNG
- Small promo tile: 440×280 PNG (optional but recommended)
- Privacy policy URL: required because the extension declares a permission
- Permission justification: explain
offscreenis used only for in-extension Mermaid rendering and there is no network access - Single-purpose description: "Convert local Markdown files to Word .docx documents"
- Distribution: Public (or Unlisted if you want to share by direct URL only during early testing)
- Title:
- Submit for review. First-time listings typically take a few business days; updates are usually faster.
- Tag and push:
git tag chrome-extension-v<version> git push origin chrome-extension-v<version>
- GitHub Actions automatically creates or updates the GitHub Release for that tag and uploads
apps/chrome-extension/marktodocx-chrome-extension.zip.
- Reusing the same
manifest.jsonversionas a previous upload — the dashboard rejects identical versions. Always bump. - Permission requests not explained in the justification field.
- A privacy policy URL that is unreachable or that contradicts the listing.
The agent skill is published to ClawHub, the OpenClaw skill registry, and mirrored as a GitHub Release for users who do not use ClawHub.
- A GitHub account at least one week old (ClawHub's minimum age requirement).
- Install the ClawHub CLI globally:
npm install -g clawhub
- Log in once on this machine:
This opens a browser flow. For headless machines use
clawhub login
clawhub login --token <token> --no-browser.
-
Bump
apps/agent-skill/package.jsonversionand updateSKILL.mdif any user-facing parameters changed. -
From the repo root, build the standalone export:
npm install npm run export:agent-skill
Output:
apps/agent-skill/dist/marktodocx-skill/— the self-contained skill folderapps/agent-skill/dist/marktodocx-skill.zip— the distributable archive
-
Run the export verification:
npm run test:export:agent-skill
This rebuilds the export and verifies the artifact layout in a CI-safe way.
-
Publish to ClawHub.
Current ClawHub CLI versions use the top-level
publishcommand, notclawhub skill publish:cd apps/agent-skill/dist/marktodocx-skill clawhub publish . \ --workdir "$PWD" \ --slug marktodocx-skill \ --name "marktodocx-skill" \ --version <version> \ --changelog "<short release notes>" \ --tags markdown,docx,word,mermaid,export
If you prefer to stay at the repo root, this is also valid:
clawhub publish ./apps/agent-skill/dist/marktodocx-skill \ --workdir "$PWD" \ --slug marktodocx-skill \ --name "marktodocx-skill" \ --version <version> \ --changelog "<short release notes>" \ --tags markdown,docx,word,mermaid,export
The path argument must point at the exported folder, not the source
apps/agent-skill/directory. ClawHub expects aSKILL.mdat the root of that exported folder, which the export already includes.The explicit
--workdir "$PWD"is important on machines that have an OpenClaw workspace configured in~/.openclaw/openclaw.json. Without it, ClawHub can resolve.against that configured workspace instead of your current shell directory and then report misleading errors such asPath must be a folderorSKILL.md requiredeven when the exported folder is valid. -
Confirm the new version is browseable on ClawHub.
-
Tag and push:
git tag agent-skill-v<version> git push origin agent-skill-v<version>
-
GitHub Actions automatically creates or updates the GitHub Release for that tag, uses
apps/agent-skill/INTRO.mdas the release description, and uploads these assets:apps/agent-skill/dist/marktodocx-skill.zipapps/agent-skill/dist/marktodocx-skill-with-mermaid-debian-amd64.zipapps/agent-skill/dist/marktodocx-skill-with-mermaid-debian-arm64.zip
ClawHub listing note: apps/agent-skill/SKILL.md is the registry-facing copy that ClawHub renders from the exported skill. If you add screenshots there, use absolute public image URLs rather than repo-relative paths so the listing still renders correctly outside the repository checkout.
Mermaid-enabled exports are platform-specific because they vendor a Chromium binary built for the export host. If you want to publish a Mermaid-enabled variant:
- Run the Mermaid export profile on the target deployment platform:
npm run export:agent-skill:mermaid
- Verify the export with the Mermaid layout check:
The export pipeline prunes Chromium's Google Docs reading-mode accessibility helper files before packaging. They are not used by headless Mermaid rendering, and removing them avoids ClawHub or VirusTotal heuristics that can flag the vendored browser bundle for dynamic-code execution. The deployed skill also repairs stripped execute bits on bundled Chromium launcher/helper files before Puppeteer launches, which avoids
npm run test:export:agent-skill:mermaid
EACCESfailures on registries or unzip flows that do not preserve Unix file modes. - Publish to ClawHub as a separate slug or version tag (e.g. add a
with-mermaid-linux-x64tag), so users on other platforms do not accidentally install a binary that does not run. - The GitHub Release automation for
agent-skill-v<version>tags already uploads Mermaid-enabled assets clearly labelled with the host OS and architecture:marktodocx-skill-with-mermaid-debian-amd64.zipandmarktodocx-skill-with-mermaid-debian-arm64.zip.
The standard export keeps Mermaid disabled and fails clearly if the deployed skill encounters a Mermaid block. That behavior is intentional — see apps/agent-skill/README.md for the full Mermaid story.
error: unknown command 'publish'underclawhub skill: your CLI is on the newer command layout. Useclawhub publish, notclawhub skill publish.Error: Path must be a folder: verify you are passing the exported directory itself, not the zip file or the sourceapps/agent-skill/folder. If your machine has an OpenClaw workspace configured, add--workdir "$PWD"so ClawHub resolves the publish path from the current shell directory instead of the configured workspace root.Error: SKILL.md required: on affected machines this can be the same workdir-resolution problem, not a missing file. IfSKILL.mdexists in the exported folder, rerun from inside that folder withclawhub publish . --workdir "$PWD" ....VirusTotal suspiciousonbrowser/.../resources/accessibility/reading_mode_gdocs_helper/gdocs_script.js: that file comes from Puppeteer's bundled Chromium, not from skill code. Rebuild with the current export script so the publish artifact prunes Chromium's nonessential Google Docs reading-mode helper before packaging, then republish the Mermaid-enabled skill.Failed to launch the browser process ... EACCESonchromeorchrome_crashpad_handler: older Mermaid-enabled exports could lose execute bits after registry packaging or extraction. Rebuild and republish with the current runtime, which repairs those permissions automatically before Puppeteer launch.GitHub API rate limit exceeded: the publish command reached a GitHub-backed metadata lookup limit. Wait for the reset window shown by ClawHub and rerun the same command. If it keeps happening, authenticate first withclawhub loginand verify withclawhub whoamibefore retrying.
The SKILL.md frontmatter sets disable-model-invocation: true. This is intentional: the skill writes files and should be invoked explicitly, not opportunistically picked up by a model in the background. Document this clearly in any ClawHub release notes so users know they must invoke marktodocx-skill by name.
The CLI is intentionally source-only. There is no npm release for it.
- Entry point:
md-to-docx.mjsat the repo root. - Install: clone the repository and run
npm install. - Use:
node md-to-docx.mjs <input.md>. - Mermaid: install the optional
@marktodocx/runtime-node-mermaidpackage or runnpx puppeteer browsers install chromeper the root README.
The root package.json is and should remain private: true. Do not add a bin entry, do not publish the root workspace to npm, and do not set up a GitHub Release artifact for the CLI on its own — its release surface is the repository itself. Major CLI behavior changes are surfaced through commit history and the root README.md CLI section.
If we ever decide to ship a real npm CLI, it will live under packages/cli/ as its own publishable workspace, with its own package.json, bin, files, and prepublishOnly build. That is intentionally out of scope today.
- Output parity is the hard ship-gate. Run
npm run test:parity:allbefore any publish, regardless of which host is going out. - Host versions are independent, but if a fix lands in
@marktodocx/coreor one of the runtime packages and changes user-visible output, plan to release all affected hosts in the same window so users do not get split behavior across tools. - Release order recommendation when shipping a coordinated change:
- Tag the merge commit on
main. - Publish the agent skill to ClawHub (slowest registry to refresh, fastest to verify with a one-line install).
- Publish the Chrome extension (slowest to verify because of Web Store review).
- Publish the VS Code extension last (fastest review, easiest to roll forward).
- Tag the merge commit on
- Update root
README.mdif a host's listing URL changes or a registry status changes (for example, the first time a host is actually live on its registry).