← Back to Main Contributing Guide
Extensions add specific features to Jan as self-contained modules.
- Assistant CRUD operations
src/index.ts- Main implementation
- Message handling, conversation state
src/index.ts- Chat logic
- Model downloads with progress tracking
src/index.ts- Download logicsettings.json- Download settings
- Local model inference via llama.cpp
src/index.ts- Entry pointsrc/backend.ts- llama.cpp integrationsettings.json- Model settings
mkdir my-extension
cd my-extension
yarn initmy-extension/
├── package.json
├── rolldown.config.mjs
├── src/index.ts
└── settings.json (optional)
import { Extension } from '@janhq/core'
export default class MyExtension extends Extension {
async onLoad() {
// Extension initialization
}
async onUnload() {
// Cleanup
}
}# Build extension
yarn build
# Run tests
yarn testasync onLoad() {
this.registerService('myService', {
doSomething: async () => 'result'
})
}async onLoad() {
this.on('model:loaded', (model) => {
console.log('Model loaded:', model.id)
})
}- Jan starts → Discovers extensions
- Loading → Calls
onLoad()method - Active → Extension responds to events
- Unloading → Calls
onUnload()on shutdown
# Check if extension loaded
console.log(window.core.extensions)
# Debug extension events
this.on('*', console.log)
# Check extension services
console.log(window.core.api)Extension not loading?
- Check package.json format:
@janhq/extension-name - Ensure
onLoad()doesn't throw errors - Verify exports in index.ts
Events not working?
- Check event name spelling
- Ensure listeners are set up in
onLoad()
- Keep extensions focused on one feature
- Use async/await for all operations
- Clean up resources in onUnload()
- Handle errors gracefully
- Don't depend on other extensions
- @janhq/core - Core SDK and extension system
- TypeScript - Type safety
- Rolldown - Bundling