[data-reveal]{opacity:1!important;transform:none!important}
Extending
AI assistant

Extending

Teach the assistant about your module with skills, give it the Builder, and read its owner-only routes.

Ship skills with your module

The assistant loads the skills of every loaded module. To teach it how your module works, ship a skill in your package and declare it:

Write the skill

skills/my-module/SKILL.md
---
name: my-module
description: Explains when and how to use my-module. Use when the user mentions invoices, billing pages, or the InvoiceService.
icon: i-lucide-receipt
category: billing
tags: [invoices, billing, pages]
---

# my-module

When to use it, its key APIs and pages, and its gotchas. Link to the docs for the rest.

The catalog reads name, description, icon, category and tags (an inline list). The description is what makes the agent pick the skill: name the cases that should trigger it.

Declare it

package.json
{
  "files": ["dist", "skills"],
  "antelopeJs": {
    "skills": ["./skills"]
  }
}

Restart

Restart the backend: the module passes every declared skill directory to the sidecar, which lists it on the Skills page.

The same declaration lets the antelopejs plugin sync your skills into a project's .claude/skills/ for Claude Code, or .agents/skills/ for Codex, outside the dashboard.

The Builder integration

When @antelopejs/dms-builder is loaded, the sidecar exposes the Builder operations as Builder* tools and defaults new chats to Safe mode. This package's own skills, dms-builder-safe (Builder tools) and dms-ai-code-mode (Code mode), tell the agent how to use them; both defer to the core dms-best-practices skill for what a page is made of.

Owner-only routes

Every route below requires an owner. Lists and settings answer 503 { message } while the sidecar is down; charts answer empty.

RoutePurpose
GET /ai/status, POST /ai/sidecar/restartLive status (offline when the sidecar does not answer), and a restart
GET /ai/status/facts, /ai/status/bannerThe Overview's status rows and banner (204 when all is well)
GET /ai/metrics/kpi/:metric, series, allowed, top-tools, usage, usage/summaryThe Overview's and Settings' figures
GET /ai/activity, /ai/activity/:id, /ai/activity/export.csvThe audit log, one call, the CSV export
GET /ai/changes, /ai/changes/:id, /ai/changes/:id/undo-preview, /ai/changes/:id/undo-confirmChange sets, a diff, what Undo restores, its dialog
POST /ai/changes/:id/undo, /ai/changes/:id/redoUndo ({ includeLater? }) and Redo
GET /ai/skills/catalog, /ai/skills/conflictsThe skills, and the duplicate-name banner
GET / PUT /ai/settingsThe settings form; PUT takes one field
GET /ai/channel/events, POST /ai/channel/:connectionId/messagesThe chat's event stream and client messages

Roles

The Assistant pages are built from DMS blocks; a custom component is used only where no block draws the screen. Every page, block and child carries $dms_ai.* metadata, so the role editor lists them with translated names.

Frontend

The chat panel, DmsAiChatPanel, is registered as a docked side panel of the dashboard (registerSidePanel), rendered once for the whole app. The command palette's assistant mode answers with DmsAiPaletteAnswer (registerCommandPaletteAssistant).