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.
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.
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/extensions-gallery.md table
Must: Include extension name, description, capabilities, and type
When: Target is Project or Global
Then: Do NOT modify extensions.json or extensions-gallery.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/extensions-gallery.md
Run npm install in packages/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
IMPORTANT: The reference files below are comprehensive but may lag behind the latest code. For the authoritative and complete API, always refer to these source files:
Source code for each built-in extension is in the AiderDesk repo at packages/extensions/extensions/[extension-name]/ — browse these for real-world patterns
When: Extension needs to display information in UI
Then: Implement getUIComponents() method
Return: Array of UIComponentDefinition objects
Use: JSX strings or external .jsx files
Built-ins: Use props.ui.CodeBlock for syntax-highlighted code, JSON, and diffs; use props.ui.ExpandableMessageBlock for collapsible tool-style message renderers
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). Use context.log only for internal diagnostics.
Note: context.log is always available; getTaskContext() returns null outside 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 MemoryEntryType enum ('task', 'user-preference', 'code-pattern')
Note: Works outside of project/task scope — pass empty strings for projectId/taskId if not applicable
Then: Use the floating placement and set name for the panel title
Must: Set name on UIComponentDefinition — used as the floating panel title bar text
Must: Use loadData: true + getUIExtensionData() for panel data; implement executeUIExtensionAction() 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