How to Implement Custom Agent Profiles in Kimi Code Using Contribution, Registry, and Catalog Extension Points

To implement custom agent profiles in Kimi Code, create a ProfileData definition, register it via definePartialInstance with the CatalogService, and let the IAgentProfileService bind it at runtime.

Kimi Code's agent architecture exposes a clean three-layer extension system that lets you add new agent profiles without modifying core engine code. This article walks through the contribution → registry → catalog pipeline, using actual source paths from the MoonshotAI/kimi-code repository.

Understanding the Three-Layer Architecture

Kimi Code organizes profile discovery through three distinct layers:

  • Contribution — A module that exports a static object describing the profile
  • Registry — The CatalogService that discovers all contributions at startup
  • Catalog — The runtime lookup performed by IAgentProfileService

The built-in implementation in packages/agent-core-v2/src/kosong/provider/providers/kimi/kimi.contrib.ts demonstrates this pattern. The CatalogService at packages/agent-core-v2/src/kosong/model/catalogService.ts registers each contribution under CatalogService.register, and the profile service at packages/agent-core-v2/src/agent/profile/profile.ts calls catalog.get(profileName) to retrieve and bind definitions.

Step 1: Create a Profile Definition

Start by defining your profile data. Create a new TypeScript file in a custom provider folder, such as packages/agent-core-v2/src/kosong/provider/providers/my-profile/myProfile.contribute.ts.

Export a constant that satisfies the ProfileData type defined in packages/agent-core-v2/src/kosong/model/catalog.ts:

import type { ProfileData } from '#/kosong/model/catalog';

export const myProfile: ProfileData = {
  profileName: 'my-assistant',
  systemPrompt: 'You are a helpful assistant that always speaks in rhymes.',
  modelAlias: 'gpt-4o-mini',
  thinkingLevel: 'off',
  disallowedTools: ['FileSystem'],
};

Key ProfileData fields include:

  • profileName — Unique identifier for the profile
  • systemPrompt — The agent's personality and instructions
  • modelAlias — Default model to use
  • thinkingLevel — Controls reasoning depth ('off', 'low', 'medium', 'high')
  • disallowedTools — Array of tool names to disable

Step 2: Declare the Contribution

Register your profile with the global catalog using definePartialInstance. Add this declaration at the bottom of your contribution file:

import { definePartialInstance } from '@moonshot-ai/kosong';
import { CatalogService } from '#/kosong/model/catalogService';

definePartialInstance(CatalogService, {
  add: (catalog) => catalog.register(myProfile),
});

This mirrors the pattern in kimi.contrib.ts. The CatalogService automatically scans for these contributions via its contribution loader.

Step 3: Update Workspace Configuration

Ensure your new provider package is included in the build. Update both:

These changes follow the monorepo's workspace maintenance rules documented in AGENTS.md at the repository root.

Step 4: Use the Custom Profile

When creating a session, pass the profile name in your request. The IAgentProfileService performs catalog lookup, binds the configuration, and applies it to the agent runtime.

REST API example:

POST /v1/sessions/xyz/profile
Content-Type: application/json

{ "profile": "my-assistant" }

Node SDK example:

import { Klient } from '@moonshot-ai/klient';
import { Session } from '@moonshot-ai/klient/session';

async function startSession() {
  const klient = new Klient();
  const session = await Session.create(klient, { id: 'demo' });

  // Bind the custom profile
  await session.profile.bind({ profile: 'my-assistant' });

  // Session now uses custom system prompt and model
  const reply = await session.prompt('Explain photosynthesis in rhyme.');
  console.log(reply);
}

Complete Custom Profile Example

Here's a full implementation file for reference:

// packages/agent-core-v2/src/kosong/provider/providers/my-profile/myProfile.contribute.ts

import type { ProfileData } from '#/kosong/model/catalog';
import { definePartialInstance } from '@moonshot-ai/kosong';
import { CatalogService } from '#/kosong/model/catalogService';

export const myProfile: ProfileData = {
  profileName: 'code-reviewer',
  systemPrompt:
    'You are a meticulous code reviewer. Focus on security, performance, and maintainability. Always suggest concrete improvements with code examples.',
  modelAlias: 'gpt-4o',
  thinkingLevel: 'medium',
  disallowedTools: ['WebSearch', 'CodeExecution'],
};

definePartialInstance(CatalogService, {
  add: (catalog) => catalog.register(myProfile),
});

Step 5: Verify Your Implementation

Run the existing test suite to validate the contribution pipeline:

pnpm test packages/agent-core-v2/test/_base/contribution/registry.test.ts

Consider adding a dedicated test to assert that catalog.get('my-assistant') returns expected data and binds without errors.

Debug your bound profile via the API:

GET /api/v1/sessions/demo/profile

The response includes the resolved ProfileData with system prompt, model alias, and all configuration fields.

Key Source Files Reference

File Role
packages/agent-core-v2/src/agent/profile/profile.ts Implements IAgentProfileService; performs profile lookup and binding
packages/agent-core-v2/src/kosong/model/catalog.ts Declares the ProfileData interface
packages/agent-core-v2/src/kosong/model/catalogService.ts Central registry; provides catalog.get(name) and register()
packages/agent-core-v2/src/kosong/provider/providers/kimi/kimi.contrib.ts Reference implementation of built-in profiles
packages/agent-core-v2/test/_base/contribution/registry.test.ts Validates contribution loading

Summary

  • Custom agent profiles extend Kimi Code through the contribution → registry → catalog pipeline
  • Define profiles using the ProfileData interface from catalog.ts
  • Register via definePartialInstance with CatalogService.register
  • The IAgentProfileService binds profiles at runtime using catalog.get()
  • Update pnpm-workspace.yaml and flake.nix for new provider packages
  • Test using the built-in contribution registry tests

Frequently Asked Questions

Can I override built-in profiles with custom ones?

Profile names must be unique within the catalog. The CatalogService throws if you attempt to register a duplicate name. To extend an existing profile, create a new name and reference the base configuration in your systemPrompt or use composition patterns in your contribution file.

What happens if a requested profile isn't found?

According to the source in profile.ts, the IAgentProfileService attempts catalog.get(profileName) and fails with a clear error if no match exists. The error propagates to the session creation or profile binding call, allowing you to catch and handle missing profiles gracefully.

Can profiles be defined in JSON instead of TypeScript?

The CatalogService registers ProfileData objects directly. While the built-in contributions use TypeScript for type safety and definePartialInstance integration, you can load JSON definitions and wrap them in a TypeScript contribution file that calls catalog.register(). The runtime only sees the resolved object.

How do I restrict which tools an agent can use?

Use the disallowedTools array in your ProfileData. List tool names exactly as registered in the tool registry. The agent runtime consults this list before executing any tool call, rejecting attempts to use forbidden tools with an appropriate error message.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →