Skip to content

Your First Plugin

In this tutorial, you’ll create a simple plugin that adds a custom tab to work unit detail views. This tab will display a welcome message and demonstrate the basics of plugin development.

  • Aether development environment set up (Setup Guide)
  • Basic TypeScript/React knowledge
  • Familiarity with terminal/command line

Use the built-in generator to create your plugin:

Terminal window
npm run create:plugin

When prompted:

  • Plugin name: hello-world
  • Description: My first Aether plugin

This creates:

packages/plugins/hello-world/
├── package.json
├── tsconfig.json
└── src/
├── index.ts
├── manifest.ts
└── components/

Create packages/plugins/hello-world/src/components/HelloTab.tsx:

import { Card, Text, Title, Stack } from '@mantine/core';
export function HelloTab() {
return (
<Card shadow="sm" padding="lg" radius="md" withBorder>
<Stack gap="md">
<Title order={2}>Hello from your first plugin!</Title>
<Text>
Congratulations! You've successfully created and registered
a custom plugin tab in Aether.
</Text>
<Text c="dim">
This tab appears on all work unit detail views where this
plugin is enabled.
</Text>
</Stack>
</Card>
);
}

Update packages/plugins/hello-world/src/manifest.ts:

import { definePlugin, ExtensionType } from '@aether/plugins-core';
import { IconWaveSawTool } from '@tabler/icons-react';
import { HelloTab } from './components/HelloTab';
export const helloWorldPlugin = definePlugin({
slug: 'hello-world',
name: 'Hello World',
version: '1.0.0',
description: 'My first Aether plugin',
author: 'Your Name',
extensions: [
{
point: 'work-unit.detail.tabs',
plugin: 'hello-world',
priority: 100,
extension: {
type: ExtensionType.TAB,
id: 'hello-tab',
label: 'Hello',
icon: IconWaveSawTool,
component: HelloTab,
},
},
],
});

Update packages/plugins/hello-world/src/index.ts:

export { helloWorldPlugin } from './manifest';
export { HelloTab } from './components/HelloTab';

The manifest registry is auto-generated, so just regenerate it:

Terminal window
npm run generate:manifests

This updates apps/web/src/lib/plugins/manifest-registry.generated.ts to include your plugin.

  1. Start the dev server:

    Terminal window
    npm run dev
  2. Navigate to Settings > Plugins

  3. Enable your plugin:

    • Find “Hello World” in the plugin list
    • Toggle it on
    • Save settings
  4. View your tab:

    • Go to any work unit (create one if needed)
    • Look for the “Hello” tab in the detail view
    • Click it to see your component!

work-unit.detail.tabs is an extension point - a specific location where plugins can add functionality. Aether has many extension points throughout the platform.

The manifest is your plugin’s configuration file. It tells Aether:

  • What your plugin is called
  • What extensions it provides
  • Where those extensions should appear
  • What components to render

priority: 100 controls tab ordering. Higher numbers appear first. The built-in tabs use priorities like:

  • Overview: 0
  • Activities: 10
  • Timer: 20

Now that you’ve built your first plugin, try:

  1. Add Context Data:

    interface HelloTabProps {
    context: {
    workUnit: any;
    workUnitId: string;
    organizationId: string;
    };
    }
    export function HelloTab({ context }: HelloTabProps) {
    return (
    <Card>
    <Text>Work Unit: {context.workUnit?.name}</Text>
    <Text>ID: {context.workUnitId}</Text>
    </Card>
    );
    }
  2. Add an Action Button: Create an ACTION extension at work-unit.detail.actions

  3. Fetch Data with tRPC: Add a server router and fetch data in your component

  4. Add Conditional Rendering: Use the match property to show your tab only for specific business types