name: extension-creator description: Create AiderDesk extensions by setting up extension files, defining metadata, implementing Extension interface methods, and updating documentation. Use when building a new extension, creating extension commands, tools, or event handlers.
Extension Creator
Create AiderDesk extensions that extend functionality through events, commands, tools, agents, and modes.
When to Use
Use this skill when:
- Building a new AiderDesk extension
- Creating extension commands, tools, or event handlers
- Implementing the Extension interface
- Setting up extension metadata and documentation
Do not use when:
- Simply activating an existing extension
- Making general code changes unrelated to extensions
- Running tests or builds
Rules
Rule: Choose installation target first
When: Starting extension creation
Then: Ask the user where to install the extension
If: Working inside the AiderDesk project (the current project is the aider-desk repository)
Then: Offer three options:
- Current Project — Install to
.aider-desk/extensions/in the current project (project-scoped) - Global — Install to
~/.aider-desk/extensions/(available in all projects) - In-Repo — Create inside
packages/extensions/extensions/(ships with AiderDesk app)
If: Working outside the AiderDesk project
Then: Offer two options:
- Current Project — Install to
.aider-desk/extensions/in the current project (project-scoped) - Global — Install to
~/.aider-desk/extensions/(available in all projects)
Must: Wait for user's choice before proceeding. The chosen target determines the entire workflow.
Reference: references/install-targets.md for full details on each target.
Rule: Follow the correct flow for the chosen target
When: User has chosen an installation target
If: Target is Current Project or Global
Then: Follow the Project / Global Flow:
- Determine extension type (single-file or folder)
- Create extension file(s) in the target directory (
.aider-desk/extensions/or~/.aider-desk/extensions/) - Implement Extension interface methods
- Export metadata and default class
- Verify the extension loads (auto-discovered, no registry needed)
If: Target is In-Repo
Then: Follow the In-Repo Flow:
- Determine extension type (single-file or folder)
- Create extension file(s) in
packages/extensions/extensions/ - Implement Extension interface methods
- Export metadata and default class
- Register in
packages/extensions/extensions.json - Document in
docs-site/docs/extensions/examples.md - Install npm dependencies if folder extension
- Verify with type checking
Rule: Determine extension type
When: Creating extension files (after target is chosen)
Then: Check if extension needs npm dependencies or multiple files
If: Extension needs dependencies or multiple files
Then: Create folder extension
If: Extension is simple with no dependencies
Then: Create single-file extension
Rule: Implement Extension interface
When: Creating extension file
Then: Implement required methods from Extension interface
Must: Define static metadata property on the class with name, version, description, author, capabilities
Must: Export class as default (e.g., export default class MyExtension implements Extension)
Never: Use @/ imports in extension files
Rule: Add UI components when needed
When: Extension needs to display UI elements in task page placements
Then: Implement getUIComponents() method
Must: Return array of UIComponentDefinition objects with id, placement, jsx
Must: Define components as JSX strings or load from .jsx files
If: Component needs data, set loadData: true and implement getUIExtensionData()
If: Component triggers actions, implement executeUIExtensionAction()
Rule: Use external libraries when UI components need npm packages
When: Extension UI components need third-party npm packages (charts, calendars, kanban boards, etc.)
Then: Implement getUIComponentsLibraries() returning a Record<string, string> mapping camelCase keys to npm package specs
Must: Access loaded libraries in JSX via props.libraries.<key>
Must: Handle the loading state — libraries are async and props.libraries.<key> will be undefined on first render
Never: Bundle or import React in library specs — AiderDesk's React instance is externalized automatically
Reference: external-libraries.md for full details, loading patterns, and examples
Rule: Add config component for extension settings
When: Extension needs user-configurable settings (shown in gear icon dialog)
Then: Implement three methods: getConfigComponent(), getConfigData(), saveConfigData()
Must: Return JSX string from getConfigComponent() — use external .jsx file for components > 20 lines
Must: Load/merge defaults in getConfigData(), persist merged data in saveConfigData()
Must: Store config file in extension directory via join(__dirname, 'config.json')
Must: Use ui.* components (ui.Input, ui.Checkbox, etc.) instead of raw HTML elements
Should: Avoid inner state (useState/useEffect) for simple form fields — read directly from config prop, call updateConfig on change. Only use local state for derived values or transient UI state.
Never: Use 'extension-settings' placement — it was removed; use the dedicated config API instead
Rule: Update registry and docs (In-Repo only)
When: Target is In-Repo and extension file is created
Then: Add entry to packages/extensions/extensions.json
Must: Include id, name, description, file or folder path, type, capabilities
Must: Set hasDependencies: true for folder extensions
Then: Add entry to docs-site/docs/extensions/examples.md table
Must: Include extension name, description, capabilities, and type
When: Target is Project or Global
Then: Do NOT modify extensions.json or examples.md — these are only for built-in extensions
Rule: Use proper TypeScript config for folders
When: Creating folder extension
Then: Include tsconfig.json with module: ES2020+
Must: Include package.json with name, version, main, dependencies
Rule: Store config in extension directory
When: Extension needs persistent config
Then: Store config files in extension directory
Never: Store config outside extension directory
Process Overview
For Project / Global targets:
- Ask user: Current Project or Global?
- Determine extension type (single-file or folder)
- Create extension file or directory structure in target dir
- Implement Extension interface methods
- Export metadata and default class
- Verify extension loads (auto-discovered)
Between steps 3 and 5:
- If extension needs config storage, create config.ts (or use inline getConfigData/saveConfigData)
- If extension has a settings UI (config component), create ConfigComponent.jsx and implement the three config methods
- If extension needs logging, create logger.ts
- If extension needs constants, create constants.ts
- If extension has placement-based UI components, create .jsx files for components (recommended for components > 20 lines)
For In-Repo target:
- Confirm user wants In-Repo (only available in aider-desk project)
- Determine extension type (single-file or folder)
- Create extension file or directory structure in
packages/extensions/extensions/ - Implement Extension interface methods
- Export metadata and default class
- Register in
packages/extensions/extensions.json - Document in
docs-site/docs/extensions/examples.md - Run
npm installinpackages/extensions/(folder extensions) - Verify with type checking
Between steps 3 and 5:
- Same optional files as Project/Global flow above
Preconditions
Before using this skill, verify:
- Installation target has been chosen by the user
- Extension purpose and required capabilities are clear
- Extension type (single-file or folder) is determined
- Extension interface and types are understood
If any precondition fails:
- Review packages/common/src/extensions.ts for types
- Check references/install-targets.md for target options
- Check references/event-types.md for event types
- Check references/command-definition.md for command structure
Postconditions
After completing this skill, verify:
- Extension implements Extension interface correctly
- Static
metadataproperty on the class includes all required fields (name, version) - Default export is the extension class
- No
@/imports used - If In-Repo: extensions.json updated correctly
- If In-Repo: docs-site/docs/extensions/examples.md updated
- If In-Repo: Type checking passes
- Extension loads without errors
- Extension appears in extensions list
- Extension capabilities work as expected
Success metrics:
- Extension loads without errors
- Extension appears in extensions list
- Extension capabilities work as expected
Common Situations
Situation: Extension needs to handle events
Pattern:
- When: Extension needs to modify agent behavior
- Then: Implement event handler methods (onAgentStarted, onToolCalled, etc.)
- Return: Partial event object to modify behavior
Situation: Extension needs to register commands
Pattern:
- When: Extension provides slash commands
- Then: Implement getCommands() method
- Return: Array of CommandDefinition objects
Situation: Extension needs to add UI components
Pattern:
- When: Extension needs to display information in UI
- Then: Implement getUIComponents() method
- Return: Array of UIComponentDefinition objects
- Use: JSX strings or external .jsx files
- Load data: Implement getUIExtensionData() if component needs data
- Handle actions: Implement executeUIExtensionAction() for user interactions
Situation: Extension needs to log messages
Pattern:
- If: Debug/internal logging (developer diagnostics, not shown to users)
- Then: Use
context.log(message, type)— logs to backend console only - If: User-visible output (showing results, status, timing info in the chat)
- Then: Use
context.getTaskContext()?.addLogMessage(level, message)— displays in task's chat UI - When ambiguous: If the user says "log", "show", "display", or "report" something, default to
addLogMessage(user-visible). Usecontext.logonly for internal diagnostics. - Note:
context.logis always available;getTaskContext()returnsnulloutside a task, so always use optional chaining (?.)
Situation: Extension needs to store or retrieve memories
Pattern:
- When: Extension wants to persist knowledge across tasks (user preferences, code patterns, architectural decisions)
- Then: Use
context.getMemoryContext()to access the Memory API - Check: Always call
isMemoryEnabled()before using memory operations - Store:
memory.storeMemory(projectId, taskId, type, content)— returns the created memory ID - Retrieve:
memory.retrieveMemories(projectId, query, limit?)— returns semantically similar memories - Types: Use
MemoryEntryTypeenum ('task', 'user-preference', 'code-pattern') - Note: Works outside of project/task scope — pass empty strings for
projectId/taskIdif not applicable - Example:
async onAgentFinished(event: AgentFinishedEvent, context: ExtensionContext) { const memory = context.getMemoryContext(); if (!memory.isMemoryEnabled()) return; const projectId = context.getProjectDir(); const taskId = context.getTaskContext()?.data.id ?? ''; await memory.storeMemory(projectId, taskId, 'code-pattern', 'Always use clsx for conditional classes'); const memories = await memory.retrieveMemories(projectId, 'React class naming'); context.log(`Found ${memories.length} relevant memories`, 'info'); }
Situation: Extension UI components need third-party npm packages
Pattern:
- When: Extension needs a library like a chart, calendar, kanban board, etc. that isn't in the built-in
uiprop - Then: Implement
getUIComponentsLibraries()returning{ key: 'package@^version' } - Access: Use
props.libraries.<key>in JSX — check forundefined(async loading) - Example:
getUIComponentsLibraries() { return { chart: 'recharts@^2.12.0' } } - Reference: external-libraries.md
Situation: Extension needs to customize message rendering
Pattern:
- When: Extension wants to replace how messages (user, assistant, tool, log, etc.) are displayed
- Then: Use the
task-messageplacement with amessageFilterto specify which messages to handle - Must: Set
messageFilter.typesto the message types to match (e.g.'user','response','assistant-group','tool','log','loading') - Must: For tool-specific filters, set
messageFilter.serverNameand/ormessageFilter.toolName - Props: Component receives
messageprop — forassistant-grouptype, accessmessage.responseMessageandmessage.toolMessages - Reference: ui-components.md for full details,
MessageFiltertype, and JSX examples
Situation: Extension needs a floating panel
Pattern:
- When: Extension needs a draggable, resizable panel (dashboard, inspector, toggle panel)
- Then: Use the
floatingplacement and setnamefor the panel title - Must: Set
nameonUIComponentDefinition— used as the floating panel title bar text - Must: Use
loadData: true+getUIExtensionData()for panel data; implementexecuteUIExtensionAction()for actions - Must: Use
context.triggerUIDataRefresh(componentId)to refresh panel data,context.triggerUIComponentsReload()to re-register components after state changes - Reference: ui-components.md for full details, including toggle panel pattern
Situation: Extension needs config storage
Pattern:
- Check: Extension needs persistent settings
- If yes: Create config.ts with loadConfig and saveConfig functions
- Store: Config files in extension directory
Situation: Extension needs a settings UI (config component)
Pattern:
- When: Extension has user-configurable options that should appear in the Settings dialog
- Then: Implement
getConfigComponent(),getConfigData(),saveConfigData()methods - JSX: Return a
.jsxfile content viareadFileSync(join(__dirname, './ConfigComponent.jsx'), 'utf-8') - Props: Component receives
{ config, updateConfig, ui, icons, models, providers, ... } - Flow: Dialog opens → loads data via getConfigData → renders JSX with props → user edits → Save calls saveConfigData
- Reference: config-components.md for full guide and examples
References
Target Selection
- install-targets.md - All three installation targets, when to use each, key differences
Flows
- project-global-flow.md - Step-by-step for Project and Global installations
- in-repo-flow.md - Step-by-step for In-Repo (packages/extensions/) installations
Technical Reference (all targets)
- packages/common/src/extensions.ts - Extension types and interfaces
- extension-interface.md - Full Extension interface, ExtensionContext, TaskContext, Metadata
- extension-types.md - Single-file vs folder extensions, examples, extensions.json format
- event-types.md - All event types and payloads
- command-definition.md - Command structure
- ui-components.md - UI component system, placements, and available components
- external-libraries.md - Loading third-party npm libraries in UI components (getUIComponentsLibraries)
- config-components.md - Config component API (settings UI), methods, JSX format, and patterns
- examples-gallery.md - Real extension examples
Assets
- templates/single-file.ts.template - Single-file template
- templates/folder-extension/ - Folder template (basic)
- templates/folder-extension-with-config/index.ts.template - Folder template with config component API
- templates/ui-component.ts.template - UI component inline template
- templates/ui-component-external.ts.template - UI component with external JSX
- templates/Component.jsx.template - Placement-based JSX component template
- templates/ConfigComponent.jsx.template - Config/settings JSX component template