Skip to content

Extension quickstart

This example adds one API 2 page at /acme-inventory. Replace the sample identity with the permanent ID assigned to your partner application.

1. Register a provider

In the partner app's hooks.py, declare Yukon and the manifest provider:

required_apps = ["yukon_crm"]

yukon_extensions = ["acme_inventory.extension.get_manifest"]

export_python_type_annotations = True
require_type_annotated_api_methods = True

2. Return a deterministic manifest

acme_inventory/extension.py
from __future__ import annotations

from typing import Any


def get_manifest() -> dict[str, Any]:
    return {
        "id": "acme_inventory",
        "title": "Acme Inventory",
        "version": "0.1.0",
        "api_version": "2",
        "description": "Show approved inventory context inside Yukon.",
        "publisher": "Acme Systems",
        "maturity": "beta",
        "entrypoint": "/assets/acme_inventory/extension.mjs?v=0.1.0",
        "required_roles": ["Acme Inventory User"],
        "navigation": [
            {
                "key": "home",
                "label": "Inventory",
                "path": "/acme-inventory",
                "icon": "package",
                "order": 80,
            }
        ],
    }

The provider must be side-effect free. Do not call a remote service, write records, or depend on the current browser while returning the manifest.

The sample also assumes the application ships an app-owned Acme Inventory User role and assigns it to the intended users. Do not remove the role filter merely to make the navigation appear.

3. Activate the page

acme_inventory/public/extension.mjs
function createPage(context) {
  const { h } = context.ui

  return {
    name: 'AcmeInventoryHome',
    setup() {
      return () => h('section', { class: 'page' }, [
        h('header', { class: 'page-header' }, [
          h('div', null, [
            h('h1', null, 'Inventory'),
            h('p', null, 'Approved inventory context for this workspace.'),
          ]),
        ]),
      ])
    },
  }
}

export function activate(context) {
  context.registerRoute({
    path: '/acme-inventory',
    name: 'acme_inventory.home',
    component: createPage(context),
  })
}

Build the Frappe assets, migrate the test site, and enable the beta extension from Yukon's Extensions settings. Verify it with a user who holds the declared role and with one who does not.

Continue with the manifest and frontend contract.