Skill: Create Extensions
Use this skill when
- You want to create a new Lucid editor extension package.
- You want the tool to scaffold a project with
lucid-packageandlucid-extension-sdk. - You do not want to modify an existing extension. Use the edit skill for that instead.
Copyable skill
Copy the full block below, including the frontmatter. (This was written for claude. It may need some minor tweaks for other coding tools)
---
name: lucid-extension-create
description: Scaffold and run a Lucid editor extension using lucid-package and lucid-extension-sdk. Use when the user asks to create a Lucid extension, start a new Lucid editor extension, or build an extension for Lucid (lucid.app / Lucidchart / Lucidspark). Not for modifying an existing extension's code.
---
# Create a Lucid Editor Extension
Use this skill to bootstrap a new Lucid editor extension. Official docs: https://lucid.readme.io/docs/editor-extensions
## Ground rules
- Always use the npm packages **`lucid-package`** and **`lucid-extension-sdk`**.
- Always use **pnpm**. Pass `--mode pnpm` to `lucid-package` **before** the subcommand.
- Correct: `npx lucid-package@latest --mode pnpm create my-pkg --with-extension my-ext`
- Wrong: `npx lucid-package@latest create --mode pnpm my-pkg`
- Before recommending versions, check the latest:
```
pnpm view lucid-package version
pnpm view lucid-extension-sdk version
```
- **Ignore the `[email protected]` line.** Versions `1.0.0`–`1.0.5` were published in December 2021 and abandoned — active development lives on the `0.0.x` track and the `latest` dist-tag points there (currently `0.0.456`). But `1.0.5` is the highest semver on npm, so a bare `pnpm add lucid-extension-sdk` (no `@latest`) resolves to the ancient `1.x`. The scaffolder sometimes does this. After scaffolding, check the installed version — if it starts with `1.`, replace it:
```
pnpm add lucid-extension-sdk@latest
```
and pin the version in `package.json` to the `0.0.x` value (e.g. `"lucid-extension-sdk": "0.0.456"`) rather than a `^1.0.5` caret range.
- Use the **non-interactive** flags on `create` (`--with-extension`, `--framework`, `--empty`, etc.) so the skill can run the scaffold itself. Only fall back to the interactive form if the user explicitly asks for it.
## Picking a framework
When asked to recommend, **default to `none`** unless the modal or panel needs real client-side state/routing:
- `none` — fine for modals loaded via `client.showModal(title, width, height, htmlString)` with an HTML resource raw-loaded at build time. Dramatically leaner: no extra dev server, no react-app subpackage, no second port. Right choice for calculators, forms, pickers, one-shot prompts.
- `react-js` / `react-ts` — only when the UI has meaningful stateful interactivity, multiple views, or existing React components to reuse. These pull in `create-react-app` (deprecated), require a parallel React dev server on port 3000, and add ~1300 packages.
- `angular` — only if the user explicitly wants Angular.
## Workflow
### 1. Collect parameters from the user
Before running any scaffold command, ask the user for:
1. **Package name** (the new directory to create, e.g. `my-lucid-package`).
2. **What to include.** At minimum an editor extension — ask for its name (e.g. `my-ext`). Optionally also shape libraries or data connectors.
3. **Framework** for the editor extension, one of: `none`, `angular`, `react-js`, `react-ts`. Recommend `none` unless they describe a stateful UI (see above).
Do not guess these — ask.
### 2. Check latest package versions
Run the two `pnpm view` commands above and note the versions. Mention them to the user so they know what will be installed.
### 3. Scaffold the package (non-interactive)
Always start with `create` — this initializes the package. Use the non-interactive flags so no prompts appear:
```
npx lucid-package@latest --mode pnpm create <package-name> \
--with-extension <extension-name> \
--framework <none|angular|react-js|react-ts>
```
Repeatable flags for additional components:
- `--with-extension <name>` (add more editor extensions)
- `--with-shape-library <name>`
- `--with-data-connector <name>`
- `--empty` — create a package with no components at all
To add an editor extension to an **existing** package later:
```
npx lucid-package@latest --mode pnpm create-editor-extension <name>
```
### 4. Verify the scaffold and repair known partial failures
`create` has a history of exiting with code 1 *after* generating the source tree — don't treat a non-zero exit as "nothing got created." Always inspect the directory. Two recoverable failures to check for:
1. **`ENOENT: mkdir '.../public/<ext-name>'`** (only with `react-js` / `react-ts` frameworks) at the end of `create`. Recovery: `mkdir -p <package>/public/<ext-name>`. No re-run needed.
2. **Unreplaced placeholder tokens** (only with `react-js` / `react-ts` frameworks). The templater leaves `DYNAMICNAME` in both `editorextensions/<ext>/src/extension.ts` and `editorextensions/<ext>/webpack.config.js`, and `REACTBUILDCOMMAND` in `webpack.config.js`. Replace:
- `DYNAMICNAME` → the extension name
- `REACTBUILDCOMMAND` → `npm run build`
Expected files after create (and repair):
- `manifest.json`
- `package.json` with `lucid-extension-sdk` as a dependency
- `editorextensions/<ext-name>/src/extension.ts` (plus framework files for `angular` / `react-*`)
- `editorextensions/<ext-name>/resources/`
- `webpack.config.js`, `tsconfig.json`
If any are genuinely absent (not just named differently), re-run `create` in a fresh directory rather than hand-building them.
### 5. Prune the generated manifest
The scaffolded `manifest.json` requests a maximal scope set (typically `READ, WRITE, DOWNLOAD, SHOW_MODAL, CUSTOM_UI, NETWORK`). Cut it down to what the extension actually uses — e.g., a modal-only extension needs just `SHOW_MODAL`. Unused scopes trigger permission prompts in the editor and fail review when shipped.
### 6. Start the dev server
```
npx lucid-package@latest --mode pnpm test-editor-extension
```
This serves editor extensions at `localhost:9900` (and any shape libraries at `localhost:9901`) and watches for changes. For `react-*` frameworks, first run `npm start` inside `editorextensions/<ext>/react-app/` in another terminal — the webpack config fetches from `localhost:3000` on watch.
### 7. Loading in Lucid (share with the user)
1. Enable developer mode in account settings (upper right of lucid.app → "Enable developer tools"), or have an admin assign the developer role.
2. In the editor: Developer menu → "Enter developer mode" — connects to the local debug server automatically.
3. Chrome 142+: may need to click the address-bar lock icon and set "Local network access" → Allow.
4. Safari is not supported for local loading — use Chrome.
## Command reference
All commands use `--mode pnpm` placed **before** the subcommand. `build-editor-extension` and `watch-editor-extension` require the extension name as an argument.
| Purpose | Command |
|---|---|
| Scaffold a new package | `npx lucid-package@latest --mode pnpm create <pkg> --with-extension <ext> --framework <none\|angular\|react-js\|react-ts>` |
| Add an extension to an existing package | `npx lucid-package@latest --mode pnpm create-editor-extension <name>` |
| Dev server (watch + serve) | `npx lucid-package@latest --mode pnpm test-editor-extension` |
| Production build / type check | `npx lucid-package@latest --mode pnpm build-editor-extension <ext>` |
| Bundle for upload | `npx lucid-package@latest --mode pnpm bundle` |
## manifest.json notes
Each extension declares:
- `name`, `title`, `codePath` (usually `bin/extension.js`)
- `products`: subset of `["chart", "spark", "teamspaces"]`
- `scopes`: any of `READ`, `WRITE`, `SHOW_MODAL`, `CUSTOM_UI`, `DOWNLOAD`, `NETWORK`, `OAUTH_TOKEN`, `USER_INFO`
Request only the scopes the extension actually uses (see step 5).
## Troubleshooting
- **Dev server runs but editor doesn't pick it up** → ensure developer mode is enabled in account settings, then re-enter developer mode in the editor.
- **Connection blocked on Chrome 142+** → allow local network access (step 7, callout 3).
- **Safari** → switch to Chrome.
- **`update-sdk` doesn't bump `lucid-extension-sdk`.** It often only trims ancillary deps. If the version didn't move, run `pnpm add lucid-extension-sdk@latest` inside the extension directory directly.
- **`ERR_PNPM_NO_MATCHING_VERSION` on `pnpm add <pkg>@latest`.** The user has `minimumReleaseAge` set in pnpm config and `latest` was published inside that window (often <72h). Options: install the previous published version (see `pnpm view <pkg> versions`), or add the package to `minimumReleaseAgeExclude`.
- **`@1.x` of `lucid-extension-sdk` got installed** → see ground-rules bullet; pin to the `0.0.x` `latest` instead.
- **pnpm not installed** Ask user if they want to install or would prefer to use npmUpdated about 14 hours ago