# How to Create Custom Skills for Kimi Code: A Complete Developer's Guide

> Learn to create custom skills for Kimi Code using Markdown and YAML. This developer's guide covers storing and invoking your custom skills via slash commands or the Node SDK.

- Repository: [Moonshot AI/kimi-code](https://github.com/MoonshotAI/kimi-code)
- Tags: how-to-guide
- Published: 2026-07-27

---

**You create custom skills for Kimi Code by authoring Markdown files with YAML front matter defining a `name` and `description`, storing them in project-specific `skills/` directories or the user-wide `~/.kimi-code/skills/` folder, and invoking them via slash commands or the Node SDK.**

Kimi Code, the open-source AI coding agent developed by MoonshotAI, extends LLM capabilities through reusable prompting logic called "skills." Creating custom skills for Kimi Code allows you to encapsulate repetitive tasks, specific linting workflows, or project conventions into invocable commands that integrate seamlessly with the agent's session management.

## Understanding the Skill Structure

In Kimi Code, a skill is formally defined by the `SkillDefinition` interface located in [`packages/agent-core/src/skill/types.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/agent-core/src/skill/types.ts). Each skill is a Markdown file containing a front-matter block with metadata and a body that serves as the prompt template.

The core structure includes:

- **`name`**: The unique identifier used in slash commands (e.g., `write-goal`)
- **`description`**: Human-readable summary displayed in the skill picker UI
- **`content`**: The prompt template (the Markdown body sent to the LLM)
- **`metadata`**: Optional settings including `type`, `whenToUse`, and invocation policies
- **`source`**: Origin classification (`project`, `user`, `extra`, or `builtin`)

## Where to Store Custom Skills

Kimi Code discovers skills from four distinct sources during session initialization. The `SessionSkillRegistry.loadRoots()` method in [`packages/agent-core/src/skill/registry.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/agent-core/src/skill/registry.ts) scans these locations:

- **Project**: Place skills in `<repo-root>/skills/` or any directory specified in the `extra_skill_dirs` configuration option. These are visible only to the current project.
- **User**: Store personal skills in `~/.kimi-code/skills/` (or the path set via the `KIMI_CODE_USER_SKILLS` environment variable). These apply across all projects for a single user.
- **Extra**: Additional directories passed via configuration, useful for admin-managed skill bundles.
- **Built-in**: Reference templates provided by the engine in `packages/agent-core/src/skill/builtin/` (e.g., [`write-goal.md`](https://github.com/MoonshotAI/kimi-code/blob/main/write-goal.md), [`update-config.md`](https://github.com/MoonshotAI/kimi-code/blob/main/update-config.md)).

## Writing a Custom Skill Definition

Skills are Markdown files with YAML front matter. At minimum, you must specify `name` and `description`. Additional fields control invocation behavior:

- **`type`**: Set to `prompt` (default, user-only) or `inline` (allows automatic model invocation)
- **`disableModelInvocation`**: Set to `true` to prevent the LLM from calling the skill automatically
- **`whenToUse`**: Human-readable hint describing the skill's purpose

```markdown
---
name: lint-changed
description: Run ESLint on modified TypeScript files
type: prompt
disableModelInvocation: false
whenToUse: "When the repository contains uncommitted TypeScript changes"
---
Run the following command in the project root and capture the output:

```bash
npx eslint {{changedFiles}}

```

If ESLint reports errors, summarize them for the user and suggest fixes.

```

## How the Engine Discovers Skills

When a session starts, the registry executes `discoverSkills` (implemented in [`packages/agent-core/src/skill/scanner.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/agent-core/src/skill/scanner.ts)) to walk the configured skill roots. For each `*.skill.md` or `*.md` file with valid front matter, the scanner builds a `SkillDefinition` object.

The registry then indexes skills using `normalizeSkillName()` and stores them in a map keyed by the normalized name. If a skill belongs to a plugin, `indexPluginSkill()` additionally indexes it by plugin ID. This process is triggered during `SessionSkillRegistry.loadRoots()` at lines 41-58 of [`packages/agent-core/src/skill/registry.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/agent-core/src/skill/registry.ts).

## Activating and Using Custom Skills

### Via Slash Commands

Type `/` followed by the skill name and optional arguments:

```

/lint-changed src/**/*.ts

```

The `skill_activation` event defined in [`packages/protocol/src/events.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/protocol/src/events.ts) triggers the registry to resolve the skill name. The `expandSkillParameters` function in [`packages/agent-core/src/skill/parser.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/agent-core/src/skill/parser.ts) handles template substitution for placeholders like `{{changedFiles}}`.

### Programmatically with the Node SDK

Use the REST API endpoints exposed through the SDK:

```typescript
import { KimiHarness } from '@moonshot-ai/kimi-code-sdk';

async function runSkill() {
  const harness = await KimiHarness.create();
  const session = await harness.session('my-session-id');

  // List available skills
  const { skills } = await session.get('/v1/sessions/my-session-id/skills');
  console.log('Available:', skills.map(s => s.name));

  // Activate with arguments
  await session.post(
    `/v1/sessions/my-session-id/skills/${encodeURIComponent('lint-changed')}:activate`,
    { args: 'src/**/*.ts' }
  );
}

```

The SDK forwards requests to `/v1/sessions/{id}/skills/{skill_name}:activate`, which the server translates into a `skill.activated` event per the schema in [`packages/protocol/src/events.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/protocol/src/events.ts).

### From a Plugin

If your skill belongs to a plugin, include an `instructions` field in the plugin manifest. When rendered, `SessionSkillRegistry.renderSkillPrompt` (lines 100-106 of [`packages/agent-core/src/skill/registry.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/agent-core/src/skill/registry.ts)) wraps these instructions in a `<kimi-plugin-instructions>` XML block, allowing the model to access plugin-specific guidance.

## Summary

- **Skills are Markdown files** with YAML front matter stored in project `skills/`, user `~/.kimi-code/skills/`, or configured extra directories.
- **Discovery happens automatically** via `SessionSkillRegistry.loadRoots()` and the scanner in [`packages/agent-core/src/skill/scanner.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/agent-core/src/skill/scanner.ts), which indexes skills by normalized name.
- **Control invocation behavior** using `type: inline` for automatic model execution or `disableModelInvocation: true` to restrict skills to manual use.
- **Activate via slash commands** (`/skill-name args`) or the REST API endpoint `/v1/sessions/{id}/skills/{name}:activate`.
- **Use built-in examples** in `packages/agent-core/src/skill/builtin/` as templates for your own implementations.

## Frequently Asked Questions

### What file extension should I use for Kimi Code skills?

Use [`.skill.md`](https://github.com/MoonshotAI/kimi-code/blob/main/.skill.md) or standard `.md` files containing YAML front matter with at minimum a `name` and `description` field. The scanner in [`packages/agent-core/src/skill/scanner.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/agent-core/src/skill/scanner.ts) automatically detects and parses these files from configured skill roots during session initialization.

### Can I prevent the model from automatically invoking my skill?

Yes. Set `disableModelInvocation: true` in the skill's front matter. This restricts the skill to manual activation via slash commands or the Node SDK, ensuring the LLM never calls it automatically during conversation turns. Alternatively, use `type: prompt` (the default) instead of `type: inline`.

### How do I pass dynamic values to a custom skill?

Include template placeholders like `{{variableName}}` in the Markdown body. When invoking via the SDK, pass arguments in the `args` field of the request body; for slash commands, append arguments after the command name. The `expandSkillParameters` function in [`packages/agent-core/src/skill/parser.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/agent-core/src/skill/parser.ts) handles the substitution at runtime.

### Where can I find example skill templates?

Reference the built-in skills located in `packages/agent-core/src/skill/builtin/`. These working examples, including [`write-goal.md`](https://github.com/MoonshotAI/kimi-code/blob/main/write-goal.md) and [`update-config.md`](https://github.com/MoonshotAI/kimi-code/blob/main/update-config.md), demonstrate proper front matter structure, prompt templating conventions, and metadata configuration patterns.