Skip to content

Creating an extension

Ryan M. edited this page Sep 17, 2026 · 2 revisions

Creating an extension

Host API 1 extensions are data, not programs. You write a folder and a manifest; Ordryn renders the UI and (for hooks) POSTs JSON.

Layout

my-extension/
  manifest.json    # required
  README.md        # recommended (install notes for operators)
  icon.svg         # optional
  panel.html       # optional sandboxed UI (set manifest `ui`)

Rules:

  • The folder name must equal manifest.id.
  • Drop the folder into Ordryn’s extensions directory (default data/extensions/). Hidden directories (names starting with .) are ignored.
  • Restart Ordryn after adding or changing files on disk. Manifests are not hot-reloaded.
  • One bad extension fails that folder only; others still load. Duplicate ids disable both copies.

Override the scan path with EXTENSIONS_DIR (legacy alias: MODS_DIR).

Steps

  1. Choose an id: lowercase letters, digits, and hyphens; must start with a letter; 2–33 characters (^[a-z][a-z0-9-]{1,32}$). Examples: severity, fields-demo.
  2. Create a directory named exactly that id.
  3. Add manifest.json with the required identity fields, plus fields (custom task fields), hooks + delivery (outbound notifications), ui (sandboxed panel), or a combination. See Manifest.
  4. Copy the directory to data/extensions/<id> on the Ordryn server.
  5. Restart Ordryn. Check server logs for extensions: loaded <id> or extensions: failed ….
  6. Site admin: Admin → Extensions → enable the extension → Save.
  7. Project owner: Project settings → Extensions → enable it for that project → Save. Configure secrets, triggers, and templates there if the extension has them.

Both site and project enablement are required for project-scoped behavior. Personal tasks (no project) never get custom fields. Member destinations (“Notify me”) use settings with "scope": "member" and are configured in Settings → Integrations, not on the project Extensions tab. Member destinations are blocked on kanban team boards (team webhook only).

Minimal identity

{
  "id": "severity",
  "name": "Severity",
  "version": "1.0.0",
  "host_api": 1,
  "description": "Adds a severity field to project tasks."
}

That manifest loads, but it does nothing until you add fields, hooks, and/or ui.

Field extension (minimal)

See Custom fields and the severity example.

{
  "id": "severity",
  "name": "Severity",
  "version": "1.0.0",
  "host_api": 1,
  "fields": [
    {
      "key": "level",
      "type": "enum",
      "label": "Severity",
      "show_on": ["sidebar", "kanban"],
      "options": [
        { "value": "low", "label": "Low" },
        { "value": "high", "label": "High" }
      ]
    }
  ]
}

Hook extension (minimal)

See Hooks, Delivery, and the webhook example.

{
  "id": "webhook",
  "name": "Generic webhook",
  "version": "1.0.0",
  "host_api": 1,
  "hooks": [
    { "on": "task.created" },
    { "on": "task.updated" }
  ],
  "delivery": {
    "type": "http.webhook",
    "url_from": "webhook_url",
    "format": "json"
  },
  "settings": [
    {
      "key": "webhook_url",
      "type": "secret",
      "label": "Webhook URL",
      "required": true,
      "scope": "project"
    }
  ],
  "templates": {
    "task.created": "New task {name} in {project} ({url})"
  }
}

Enablement

Layer Who What
Site Admin Admin → Extensions. Toggle Enable, Save. Failed extensions cannot be configured. Site-scoped secrets, triggers, and templates live here.
Project Project owner only Project settings → Extensions. Enable, secrets, triggers, templates. Blocked until the site toggle is on.
Member Signed-in user Settings → Integrations / Notify me, when the manifest has scope: member settings. Not used on kanban project tasks.

Editors cannot manage extensions.

An extension appears on the project Extensions tab if it has any project-scoped setting, any member-scoped setting, any custom fields, or a ui panel. Site-only hook extensions such as join-requests do not appear there.

Environment

Variable Purpose
EXTENSIONS_DIR Scan path for extension folders. Default data/extensions/.
MODS_DIR Legacy alias for EXTENSIONS_DIR.
PUBLIC_URL Public origin used to build {url} in templates (for example https://todo.example.com).
BASE_PATH Used for {url} when it is already a URL-like value and PUBLIC_URL is unset.

Set PUBLIC_URL in Ordryn’s .env so {url} is a clickable task link ({PUBLIC_URL}/tasks/{id}). For join.* events, {url} points at Admin → Join requests when PUBLIC_URL is set.

Author checklist

  • Folder name equals id
  • id, name, version, host_api present (host_api is 1)
  • Field / setting keys are unique and match the key pattern
  • Enums have options; non-enums do not
  • Hook extensions declare hooks, delivery.type, and a matching settings key for url_from
  • http.webhook sets format if you need json or content (otherwise you get {"text": "…"})
  • Project-facing settings use "scope": "project"; “Notify me” settings use "scope": "member"
  • ui, if set, is a relative HTML path that exists in the folder
  • permissions / actions are only the known values (see Callbacks and inbound)
  • Copied to data/extensions/<id> and Ordryn restarted
  • Enabled in Admin, then enabled (and configured) on a project

Clone this wiki locally