# How to Build Custom AI Assistants in AionUi by Creating Skills in the `skills/` Directory

> Learn to build custom AI assistants in AionUi. Create skills in the skills/ directory using SKILL.md and YAML frontmatter. Enable them easily for powerful AI applications.

- Repository: [OfficeAI/AionUi](https://github.com/iofficeai/aionui)
- Tags: how-to-guide
- Published: 2026-02-19

---

**You can build custom AI assistants in AionUi by creating a [`SKILL.md`](https://github.com/iOfficeAI/AionUi/blob/main/SKILL.md) file inside a folder under the `skills/` directory, adding YAML frontmatter with `name` and `description`, and enabling the skill either globally via [`assistantPresets.ts`](https://github.com/iOfficeAI/AionUi/blob/main/assistantPresets.ts) or per-conversation through the `enabledSkills` array.**

AionUi implements a modular skill system that allows you to extend AI assistant capabilities without modifying core application code. By placing structured knowledge files in the `skills/` directory, you create reusable capabilities that the system discovers, indexes, and injects into agent conversations on demand.

## Understanding the Skill Loading Pipeline

The skill system follows a strict discovery and injection pipeline defined across several core files in the AionUi source code.

### Skill Storage Locations

In [`src/process/initStorage.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/process/initStorage.ts), the application defines the canonical paths for skill storage:

```typescript
const STORAGE_PATH = { …, skills: 'skills' };
const getSkillsDir = () => path.join(cacheDir, STORAGE_PATH.skills);
const getBuiltinSkillsDir = () => path.join(getSkillsDir(), '_builtin');

```

- **`getSkillsDir()`** returns the root directory for all custom skills (typically `[cache]/skills/`).
- **`getBuiltinSkillsDir()`** points to `skills/_builtin/`, which houses system skills that are always available.

### Discovery and Indexing

The `AcpSkillManager` class in [`src/process/task/AcpSkillManager.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/process/task/AcpSkillManager.ts) handles skill discovery:

- **`discoverBuiltinSkills()`** scans the `_builtin` directory and loads all found skills automatically.
- **`discoverSkills(enabledSkills)`** scans the custom `skills/` directory but only loads skills whose names appear in the `enabledSkills` array passed to the manager.

The manager looks for skills in three possible locations:

```typescript
const builtinSkillFile = path.join(builtinSkillsDir, skillName, 'SKILL.md');
const skillDirFile    = path.join(skillsDir,      skillName, 'SKILL.md');
const skillFlatFile   = path.join(skillsDir, `${skillName}.md`);

```

After discovery, `buildSkillsIndexText()` generates a lightweight index containing the `name` and `description` from each skill's frontmatter.

### Injection into Conversations

In [`src/process/task/agentUtils.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/process/task/agentUtils.ts), the function `prepareFirstMessageWithSkillsIndex()` injects the skills index into the first message of a conversation. When the AI replies with a `[LOAD_SKILL: name]` token, `AcpSkillManager.getSkill(name)` lazily reads the full body of the matching [`SKILL.md`](https://github.com/iOfficeAI/AionUi/blob/main/SKILL.md) file and provides it to the agent.

## Creating a Custom Skill Step-by-Step

Follow these steps to build custom AI assistants by creating skills in the `skills/` directory.

### Step 1: Create the Directory Structure

Create a folder for your skill inside the `skills/` directory. The folder name should match your skill identifier:

```bash
mkdir -p skills/my-custom-assistant

```

Alternatively, you can use a flat file structure: [`skills/my-custom-assistant.md`](https://github.com/iOfficeAI/AionUi/blob/main/skills/my-custom-assistant.md).

### Step 2: Write the SKILL.md with Frontmatter

Create a [`SKILL.md`](https://github.com/iOfficeAI/AionUi/blob/main/SKILL.md) file inside your skill folder. Begin with YAML frontmatter defining the `name` and `description` fields:

```markdown
---
name: my-custom-assistant
description: Provides specialized data analysis capabilities for CSV files.
---

# Custom Data Analysis Assistant

When activated, this skill enables advanced CSV parsing and statistical analysis.

## Capabilities

- Parse malformed CSV files
- Calculate moving averages
- Generate summary statistics

```

The `name` and `description` from the frontmatter appear in the skills index injected into the first message.

### Step 3: Enable the Skill

**Option A: Global Enable via Preset**

Edit [`src/common/presets/assistantPresets.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/common/presets/assistantPresets.ts) and add your skill name to the `defaultEnabledSkills` array of your chosen preset:

```typescript
export const assistantPresets = [
  {
    id: 'cowork',
    name: 'Cowork Assistant',
    defaultEnabledSkills: ['skill-creator', 'pptx', 'docx', 'my-custom-assistant'],
    // ... other fields
  },
];

```

**Option B: Per-Conversation Enable**

Use the UI "Add Skills" button to add the skill name to the conversation's `enabledSkills` array, or set it programmatically via the API when creating an agent.

### Step 4: Verify Loading

Start a new conversation with the assistant. The first message should contain an "Available Skills" section listing your new skill:

```

[Available Skills]
- my-custom-assistant: Provides specialized data analysis capabilities for CSV files.

```

Test the lazy loading by asking the assistant to `[LOAD_SKILL: my-custom-assistant]`. The agent should then receive the full body content defined in your [`SKILL.md`](https://github.com/iOfficeAI/AionUi/blob/main/SKILL.md).

## Programmatic Skill Management

For advanced use cases, you can manage skills programmatically using the AionUi API.

### Adding a Skill Programmatically

```typescript
import { getSkillsDir } from '@/process/initStorage';
import { writeFileSync, mkdirSync } from 'fs';
import path from 'path';

// Create folder
const skillName = 'text-summarizer';
const skillFolder = path.join(getSkillsDir(), skillName);
mkdirSync(skillFolder, { recursive: true });

// Write SKILL.md
const skillFile = path.join(skillFolder, 'SKILL.md');
writeFileSync(
  skillFile,
  `---\nname: ${skillName}\ndescription: Summarises long text into a concise paragraph.\n---\n\n# Usage\nPaste any text and ask for a summary.\n`

);

```

### Enabling a Skill for a Single Conversation

```typescript
import { ProcessConfig } from '@/process/initStorage';
import type { AcpBackendConfig } from '@/types/acpTypes';

// Enable skill for a specific conversation
await ProcessConfig.set('acp.customAgents', [
  {
    id: 'custom-assistant',
    name: 'My Custom Assistant',
    enabled: true,
    isPreset: false,
    isBuiltin: false,
    enabledSkills: ['text-summarizer'],   // Enable the new skill
    presetAgentType: 'gemini',
    // other required fields …
  },
]);

```

### Loading a Skill Inside a Custom Agent

```typescript
import { AcpSkillManager } from '@/process/task/AcpSkillManager';

async function loadAndShowSkill(name: string) {
  const manager = AcpSkillManager.getInstance([name]); // ensure it’s discovered
  await manager.discoverSkills([name]);
  const skill = await manager.getSkill(name);
  if (skill?.body) {
    console.log(`Skill “${name}” body:\n`, skill.body);
  }
}
loadAndShowSkill('markdown-table-formatter');

```

## Key Files and Their Roles

| File | Role | Link |
|------|------|------|
| [`src/process/initStorage.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/process/initStorage.ts) | Defines `getSkillsDir()` and `getBuiltinSkillsDir()`; manages the user-writable skills folder and copies built-in skills. | [initStorage.ts](https://github.com/iOfficeAI/AionUi/blob/main/src/process/initStorage.ts) |
| [`src/process/task/AcpSkillManager.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/process/task/AcpSkillManager.ts) | Core manager that discovers, indexes, and lazily loads skills. Implements `discoverBuiltinSkills()`, `discoverSkills()`, and `getSkill()`. | [AcpSkillManager.ts](https://github.com/iOfficeAI/AionUi/blob/main/src/process/task/AcpSkillManager.ts) |
| [`src/process/task/agentUtils.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/process/task/agentUtils.ts) | Injects the skills index into the first chat message via `prepareFirstMessageWithSkillsIndex()` and handles `loadSkillsContent()`. | [agentUtils.ts](https://github.com/iOfficeAI/AionUi/blob/main/src/process/task/agentUtils.ts) |
| [`src/common/presets/assistantPresets.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/common/presets/assistantPresets.ts) | Defines assistant presets; contains `defaultEnabledSkills` array for globally enabling skills. | [assistantPresets.ts](https://github.com/iOfficeAI/AionUi/blob/main/src/common/presets/assistantPresets.ts) |
| [`src/renderer/hooks/usePresetAssistantInfo.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/renderer/hooks/usePresetAssistantInfo.ts) | Reads `enabledSkills` from conversation extra data for backward-compatible session management. | [usePresetAssistantInfo.ts](https://github.com/iOfficeAI/AionUi/blob/main/src/renderer/hooks/usePresetAssistantInfo.ts) |

## Summary

- **Skills** are modular knowledge units stored as [`SKILL.md`](https://github.com/iOfficeAI/AionUi/blob/main/SKILL.md) files in the `skills/` directory, discovered by [`AcpSkillManager.ts`](https://github.com/iOfficeAI/AionUi/blob/main/AcpSkillManager.ts).
- **Storage locations** are defined in [`initStorage.ts`](https://github.com/iOfficeAI/AionUi/blob/main/initStorage.ts): custom skills live in `skills/`, while built-ins reside in `skills/_builtin/`.
- **Discovery** requires enabling skills via `defaultEnabledSkills` in presets or the `enabledSkills` array per conversation.
- **Injection** happens automatically: [`agentUtils.ts`](https://github.com/iOfficeAI/AionUi/blob/main/agentUtils.ts) adds a skills index to the first message, and lazy loading occurs when the AI requests `[LOAD_SKILL: name]`.
- **Frontmatter** (`name` and `description`) in [`SKILL.md`](https://github.com/iOfficeAI/AionUi/blob/main/SKILL.md) files drives the indexing system.

## Frequently Asked Questions

### What file format should I use for skills?

Skills must be written as Markdown files named [`SKILL.md`](https://github.com/iOfficeAI/AionUi/blob/main/SKILL.md) (for folder-based skills) or `<skill-name>.md` (for flat file skills). Each file must begin with YAML frontmatter containing `name` and `description` fields, followed by the skill body content. The [`AcpSkillManager.ts`](https://github.com/iOfficeAI/AionUi/blob/main/AcpSkillManager.ts) parser specifically looks for these frontmatter keys to build the skills index.

### How do I enable a skill for all conversations?

To enable a skill globally, modify the `defaultEnabledSkills` array in [`src/common/presets/assistantPresets.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/common/presets/assistantPresets.ts). Add your skill's `name` (as defined in the frontmatter) to the array of the desired preset. For example, adding `'markdown-table-formatter'` to the `cowork` preset's `defaultEnabledSkills` makes that skill available in every new conversation using that preset.

### Can I load skills dynamically during a conversation?

Yes, skills support lazy loading via the `[LOAD_SKILL: name]` token. When the AI generates this token in a response, `AcpSkillManager.getSkill(name)` dynamically reads the full body of the specified [`SKILL.md`](https://github.com/iOfficeAI/AionUi/blob/main/SKILL.md) file and injects it into the context. This allows assistants to pull in specialized knowledge only when needed, keeping initial context windows small while retaining access to extensive capabilities.

### Where are built-in skills stored?

Built-in skills reside in the `skills/_builtin/` directory, as defined by `getBuiltinSkillsDir()` in [`src/process/initStorage.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/process/initStorage.ts). These skills are automatically copied to the user's skills folder on first run and are always loaded by `discoverBuiltinSkills()` in [`AcpSkillManager.ts`](https://github.com/iOfficeAI/AionUi/blob/main/AcpSkillManager.ts), regardless of the `enabledSkills` configuration. User-created custom skills should be placed directly in the `skills/` folder, not in the `_builtin` subdirectory.