create-extension

Scaffolds new built-in extensions with manifests, contribution points, and activation code for the Universe Editor.

Updated May 13, 2026
One-click install
npx skills add https://github.com/lovebirdsx/universe-editor --skill create-extension-lovebirdsx
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: create-extension
Source: https://github.com/lovebirdsx/universe-editor/tree/main/.claude/skills/create-extension
Command: npx skills add https://github.com/lovebirdsx/universe-editor --skill create-extension-lovebirdsx

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? Creating a new extension in the Universe Editor monorepo involves many subtle rules—manifest schema, engines.universe semver ranges, activation events, esbuild setup, and NLS localization—and mistakes cause extensions to be silently skipped by the scanner. This Skill encodes the full recipe so a new extension works on the first try. ## Core Features & Use Cases - Two-form scaffolding: Guides the choice between a declaration-only extension (just a package.json, like claude-helper) and a code extension (manifest + esbuild + src/extension.ts, like ai or numbered-bookmarks). - Contribution point reference: Covers commands, keybindings, configuration, menus, submenus, jsonValidation, and activationEvents with the exact zod-validated formats. - Pitfall prevention: Documents the engines.universe compatibility red line (custom semver, no || ranges, pre-1.0 caret locking) that silently blocks extensions, plus testing patterns with vi.mock for the extension-api facade. - Use Case: Ask the agent to create a new extension that registers a command with a keybinding and persists state via workspaceState; it produces the full directory skeleton, manifest, activation code, and tests following repo conventions. ## Quick Start Create a new built-in extension named my-feature that registers a command with a keybinding and a configuration setting, following the extensions/ai template.

Frequently Asked Questions about create-extension

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I create a new VSCode-style extension in this monorepo?

Create a directory under extensions/ with a package.json manifest declaring contributes and engines.universe. For code extensions, add esbuild.config.mjs, src/extension.ts exporting activate(context), and copy the scripts/devDependencies from extensions/ai. The scanner auto-discovers it with no manual registration.

When does an extension need activation code versus just a manifest?

Declaration-only extensions need only package.json for static contributions like jsonValidation, keybindings, or menu items. Code extensions with src/extension.ts are required only when activation must run logic such as registering command handlers, status bar items, decorations, SCM, or providers.

Why is my extension silently skipped or not loading?

The scanner skips extensions whose engines.universe range fails the custom satisfies check or whose manifest fails zod validation, logging only to the extension output channel. Use ">=0.1.0 <1.0.0" instead of ^0.1.0, since pre-1.0 caret locks the minor version and rejects 0.12.0.

What activationEvents values are supported for lazy extension activation?

Supported values are "*", "onStartupFinished", "onCommand:<id>", "onLanguage:<id>", "onView:<id>", and "onCustomEditor:<viewType>". Prefer lazy activation such as onCommand for command-based extensions, reserving onStartupFinished for globally persistent behavior.

How do I localize extension manifest strings with package.nls?

Write user-visible manifest strings as %key% placeholders, add package.nls.json for English defaults plus package.nls.<locale>.json overrides, and list all NLS files in the package.json files array. Runtime code messages use a separate localize() helper pattern instead.

How do I unit test extension code that imports the extension-api?

Use vitest with vi.mock('@universe-editor/extension-api', ...) to stub only the namespaces you use, manually providing value enums, then dynamically import the module under test after the mock. Extract logic into pure modules and test those rather than the extension.ts entry point.