Plugin API Reference
Complete reference for the Elysium plugin API. Learn about lifecycle hooks, available interfaces, and how to interact with schedule data.
On This Page
Lifecycle Hooks
Define these functions in your main.js to respond to plugin lifecycle events.
onLoad()
Called once when the plugin is first loaded. Use this for one-time setup.
function onLoad() {
console.log("Plugin loaded!");
// One-time initialization
}onEnable()
Called when the plugin is enabled. Set up event listeners and start your plugin's functionality.
function onEnable() {
// Register event listeners
elysium.events.on("task.completed", handleTaskComplete);
elysium.events.on("habit.completed", handleHabitComplete);
}onDisable()
Called when the plugin is disabled. Clean up event listeners and save state.
function onDisable() {
// Clean up
elysium.events.off("task.completed", handleTaskComplete);
elysium.events.off("habit.completed", handleHabitComplete);
}onUnload()
Called when the plugin is being completely unloaded. Final cleanup before removal.
function onUnload() {
// Final cleanup
console.log("Plugin unloaded");
}Events
Listen for events to react to user actions and schedule changes. Register listeners in onEnable().
Entity Events
// Goals
goal.created, goal.updated
goal.deleted, goal.completed
// Tasks
task.created, task.updated
task.deleted, task.completed
// Habits
habit.created, habit.updated
habit.deleted, habit.completed
// Odysseys
odyssey.created, odyssey.updated
odyssey.deleted, odyssey.completed
// Appointments
appointment.created, appointment.updated
appointment.deleted, appointment.completed
// Reminders
reminder.created, reminder.updated
reminder.deleted, reminder.completedSystem Events
// Timer
timer.started
timer.paused
timer.stopped
timer.completed
// App Lifecycle
app.didBecomeActive
app.willResignActive
app.willTerminate
// Schedule
schedule.dayStarted
schedule.itemScheduled
// Settings & Theme
settings.changed
theme.changed// Listening to events
elysium.events.on("task.completed", (task) => {
console.log("Task completed:", task.title);
});
elysium.events.on("habit.completed", (habit) => {
console.log("Habit logged:", habit.title, "Streak:", habit.streak);
});
elysium.events.on("reminder.triggered", (reminder) => {
console.log("Reminder fired:", reminder.title);
});Example: Celebrate Habit Streaks
elysium.events.on("habit.completed", (habit) => {
if (habit.streak > 0 && habit.streak % 7 === 0) {
elysium.ui.showNotification({
title: "🔥 Streak Milestone!",
message: `${habit.streak} day streak on ${habit.title}!`
});
}
});Schedule API
Access and modify schedule data using the elysium API namespaces.
elysium.tasks.*
// Get all tasks
const tasks = await elysium.tasks.list();
// Get tasks with filters
const overdue = await elysium.tasks.list({
status: "todo",
overdue: true
});
// Get a specific task
const task = await elysium.tasks.get("task-id");
// Create a new task
await elysium.tasks.create({
title: "Review pull request",
due: "2024-03-15",
tags: ["work", "code-review"]
});
// Update a task
await elysium.tasks.update("task-id", {
status: "done"
});elysium.habits.*
// Get all habits
const habits = await elysium.habits.list();
// Get habit with streak info
const habit = await elysium.habits.get("habit-id");
console.log(habit.streak, habit.bestStreak);
// Log a habit completion
await elysium.habits.complete("habit-id");
// Get completion history
const history = await elysium.habits.history("habit-id", {
days: 30
});elysium.goals.*
// Get all goals
const goals = await elysium.goals.list();
// Update goal progress
await elysium.goals.updateProgress("goal-id", {
current: 75,
target: 100
});
// Get milestones
const milestones = await elysium.goals.milestones("goal-id");elysium.odysseys.*
// Get all odysseys (multi-step journeys)
const odysseys = await elysium.odysseys.list();
// Get odyssey with steps
const odyssey = await elysium.odysseys.get("odyssey-id");
console.log(odyssey.steps, odyssey.currentStep);
// Update progress
await elysium.odysseys.advanceStep("odyssey-id");elysium.appointments.*
// Get appointments
const appointments = await elysium.appointments.list();
// Get appointments for a date range
const upcoming = await elysium.appointments.list({
from: "2024-03-15",
to: "2024-03-22"
});
// Create an appointment
await elysium.appointments.create({
title: "Team standup",
startTime: "2024-03-15T09:00:00",
endTime: "2024-03-15T09:30:00"
});elysium.reminders.*
// Get all reminders
const reminders = await elysium.reminders.list();
// Create a reminder
await elysium.reminders.create({
title: "Take medication",
time: "2024-03-15T08:00:00",
repeat: "daily"
});
// Delete a reminder
await elysium.reminders.delete("reminder-id");elysium.categories.* & elysium.tags.*
// Get all categories
const categories = await elysium.categories.list();
// Get all tags
const tags = await elysium.tags.list();
// Create a category
await elysium.categories.create({
name: "Work",
color: "#3b82f6"
});All API Namespaces
elysium.goals.* // Goals and milestones
elysium.tasks.* // Tasks and to-dos
elysium.habits.* // Habits and streaks
elysium.odysseys.* // Multi-step journeys
elysium.appointments.* // Calendar appointments
elysium.reminders.* // Time-based reminders
elysium.categories.* // Item categories
elysium.tags.* // Tags management
elysium.timeline.* // Timeline access
elysium.schedules.* // Schedule management
elysium.events.* // Event listeners
elysium.commands.* // Register commands
elysium.storage.* // Plugin data persistence
elysium.settings.* // App settings access
elysium.theme.* // Theme customization
elysium.ui.* // UI components
elysium.notifications.* // System notifications
elysium.console.* // Debug loggingTheme API
Customize Elysium's appearance with the hierarchical theme token system using elysium.theme.*.
// Get current theme colors
const colors = elysium.theme.getColors();
// Set specific color tokens
elysium.theme.setColor("primary", "#6366f1");
elysium.theme.setColor("goalColor", "#22c55e");
// Apply a complete theme
elysium.theme.apply({
colors: {
primary: "#6366f1",
secondary: "#8b5cf6",
background: "#0f0f0f",
surface: "#1a1a1a",
text: "#ffffff",
textSecondary: "#a1a1aa",
success: "#22c55e",
warning: "#f59e0b",
error: "#ef4444",
border: "#27272a"
}
});
// Reset to default theme
elysium.theme.reset();Base Color Tokens
primary
secondary
background
surface
text
textSecondary
success
warning
error
border
Entity Color Tokens
goalColor
taskColor
habitColor
odysseyColor
appointmentColor
reminderColor
Customize colors for each item type.
UI Injection
Inject custom UI components into various locations within Elysium. Requires the customize:ui permission.
// Register a widget in the sidebar
elysium.ui.registerWidget({
id: "my-widget",
location: "sidebar",
title: "My Widget",
render: () => {
return {
type: "view",
children: [
{ type: "text", content: "Hello from my plugin!" }
]
};
}
});
// Add a custom menu item
elysium.ui.addMenuItem({
id: "my-action",
location: "context_menu",
title: "My Custom Action",
icon: "star",
action: () => {
// Handle the action
}
});
// Remove injected UI when disabling
elysium.ui.removeWidget("my-widget");Injection Points
toolbar
sidebar
dashboard
quick_log
entity_detail
settings_panel
menu_bar
context_menu
empty_state
The empty_state slot appears on the Dashboard when no entity is selected.
View Injection
Inject custom card views into specific slots in the app. This is particularly useful for the empty_state slot, which appears on the Dashboard when no entity is selected. Requires the customize:ui permission.
elysium.ui.injectView()
Inject a card view into a slot. Calling again with the same id replaces the existing view.
// Inject a view into the empty state area
elysium.ui.injectView({
id: "daily-stats",
slot: "empty_state",
view: {
type: "card",
title: "Today's Progress",
content: "3 of 5 tasks completed"
}
});
// Update an existing injected view (same id replaces it)
elysium.ui.injectView({
id: "daily-stats",
slot: "empty_state",
view: {
type: "card",
title: "Today's Progress",
content: "5 of 5 tasks completed!"
}
});elysium.ui.removeView()
Remove an injected view by its ID. Each plugin can only remove its own views.
elysium.ui.removeView("daily-stats");elysium.ui.getViewsForSlot()
Get all views currently injected into a specific slot.
const emptyStateViews = elysium.ui.getViewsForSlot("empty_state");View Definition Fields
| Field | Type | Description |
|---|---|---|
type | String | View type (currently "card") |
title | String | Optional title displayed at the top of the card |
content | String | Optional body text displayed in the card |
Notes
- Each plugin's views are namespaced — a plugin can only remove its own views
- The
empty_stateslot appears alongside motivational quotes (if the user has them enabled) - Views update in real-time; call
injectViewagain with the sameidto refresh content - Clean up views in your
onDisable()lifecycle hook
Settings & Storage
Store plugin data that persists across sessions. Settings sync automatically if the user has cloud sync enabled.
// Store values
await elysium.storage.set("apiKey", "sk-...");
await elysium.storage.set("syncEnabled", true);
await elysium.storage.set("config", { theme: "dark", limit: 10 });
// Retrieve values
const apiKey = await elysium.storage.get("apiKey");
const syncEnabled = await elysium.storage.get("syncEnabled") ?? false;
// Remove a value
await elysium.storage.remove("apiKey");
// Clear all plugin storage
await elysium.storage.clear();Plugin Settings Schema
Define user-configurable settings in your manifest.json that appear in the plugin's settings panel. Settings are automatically saved to plugin storage.
"settings": [
{
"id": "enableStreakCelebration",
"type": "boolean",
"title": "Celebrate Streaks",
"description": "Show celebration messages for streak milestones",
"default": true
},
{
"id": "quoteCategory",
"type": "select",
"title": "Quote Category",
"description": "Choose the type of quotes to display",
"default": "motivation",
"options": [
{ "value": "motivation", "label": "Motivation" },
{ "value": "productivity", "label": "Productivity" }
]
},
{
"id": "customMessage",
"type": "string",
"title": "Custom Message",
"description": "A custom message to display",
"default": ""
},
{
"id": "maxNotifications",
"type": "number",
"title": "Max Notifications",
"description": "Maximum notifications per day",
"default": 5
},
{
"id": "dataPath",
"type": "folder",
"title": "Data Folder",
"description": "Select a folder for plugin data"
}
]Setting Types
| Type | Description | Properties |
|---|---|---|
boolean | Toggle switch | default: boolean |
string | Text input | default: string |
number | Numeric input | default: number |
select | Dropdown menu | default: string, options: [{ value, label }] |
folder | Folder picker | — |
Access settings values via the Storage API: elysium.storage.get("settingId")
Commands
Declare commands in your manifest.json for discoverability, then register handlers in your code.
Manifest Declaration
"commands": [
{
"id": "show-quote",
"name": "Show Daily Quote",
"description": "Display today's motivational quote"
},
{
"id": "reset-stats",
"name": "Reset Statistics",
"description": "Reset all plugin statistics"
}
]Registering Handlers
function onLoad() {
elysium.commands.register("show-quote", "Show Daily Quote", showQuoteHandler);
elysium.commands.register("reset-stats", "Reset Statistics", resetStatsHandler);
}
function showQuoteHandler() {
elysium.ui.showNotification({
title: "Daily Quote",
message: "The only way to do great work is to love what you do.",
type: "info"
});
}Notifications
Show notifications to users for important events or confirmations.
// Simple notification
elysium.ui.showNotification({
title: "Sync Complete",
message: "12 items synced successfully"
});
// With custom duration
elysium.ui.showNotification({
title: "Saved",
message: "Your changes have been saved",
duration: 3000 // milliseconds
});
// Success/error variants
elysium.ui.showSuccess("Task completed!");
elysium.ui.showError("Something went wrong");Permissions
Plugins must declare all permissions they need in manifest.json. Request only what you need—users see these when installing.
Read Permissions
read:goals
read:tasks
read:habits
read:odysseys
read:appointments
read:reminders
read:categories
read:tags
read:timeline
read:settings
read:schedules
Write Permissions
write:goals
write:tasks
write:habits
write:odysseys
write:appointments
write:reminders
write:categories
write:tags
write:timeline
write:settings
write:schedules
Special Permissions
notifications — Show system notifications
shortcuts — Register keyboard shortcuts
network — Make network requests
clipboard — Access clipboard
filesystem — Read/write files
theme — Customize appearance
customize:ui — Inject custom UI
Permission Example
"permissions": [
"read:tasks",
"write:tasks",
"read:habits",
"notifications",
"network"
]Only request permissions your plugin actually needs.
Full Access Mode
By default, Elysium enforces that plugins can only use APIs for which they declared permissions. Users can enable Full Access Mode in Settings → Plugins & Recipes to bypass these checks.
When Full Access Mode is Enabled
- Plugins can call any API without declaring the permission
- The JavaScript sandbox remains in place (plugins still can't access the filesystem outside their sandbox or execute arbitrary code)
- Useful for plugin developers testing without updating manifests
- Users who fully trust all their installed plugins can enable this for convenience
Note for developers: Even though Full Access Mode exists, you should still declare all permissions your plugin needs in the manifest. This ensures your plugin works for users who don't enable Full Access Mode, and helps users understand what your plugin does.