Loading
The system prompt architecture provides a modular, composable system for building AI assistant prompts. It supports multiple model variants, dynamic component composition, flexible tool configuration, and template-based prompt generation.
Recommended by author
# System Prompt Architecture
## Overview
The system prompt architecture provides a modular, composable system for building AI assistant prompts. It supports multiple model variants, dynamic component composition, flexible tool configuration, and template-based prompt generation.
## Developer
To generate snapshots for each variants added to the unit test in [src/core/prompts/system-prompt/__tests__/integration.test.ts](./__tests__/integration.test.ts):
```sh
npm run test:unit
```
## Directory Structure
```
src/core/prompts/system-prompt/
├── registry/
│ ├── ClineToolSet.ts # Tool set management & registry
│ ├── PromptRegistry.ts # Singleton registry for loading/managing prompts
│ ├── PromptBuilder.ts # Builds final prompts with template resolution
│ └── utils.ts # Model family detection utilities
├── components/ # Reusable prompt components
│ ├── agent_role.ts # Agent role and identity section
│ ├── system_info.ts # System information section
│ ├── mcp.ts # MCP servers section
│ ├── todo.ts # Todo management section
│ ├── user_instructions.ts # User custom instructions
│ ├── tool_use.ts # Tool usage instructions
│ ├── editing_files.ts # File editing guidelines
│ ├── capabilities.ts # Agent capabilities section
│ ├── rules.ts # Behavioral rules section
│ ├── objective.ts # Task objective section
│ ├── act_vs_plan.ts # Action vs planning mode
│ ├── feedback.ts # Feedback and improvement section
│ └── index.ts # Component registry
├── templates/ # Template engine and placeholders
│ ├── TemplateEngine.ts # [placeholder] resolution engine
│ └── placeholders.ts # Standard placeholder definitions
├── tools/ # Individual tool definitions
│ ├── spec.ts # Tool specification interface
│ ├── register.ts # Tool registration system
│ ├── index.ts # Tool exports
│ └── [tool-name].ts # Individual tool implementations
├── variants/ # Model-specific prompt variants
│ ├── generic/
│ │ ├── config.ts # Generic fallback configuration
│ │ └── template.ts # Base prompt template
│ ├── next-gen/
│ │ ├── config.ts # Next-gen model configuration
│ │ └── template.ts # Advanced model template
│ ├── xs/
│ │ ├── config.ts # Small model configuration
│ │ └── template.ts # Optimized template
│ └── index.ts # Variant registry exports
├── types.ts # Core type definitions
└── README.md # This documentation
```
## Core Components
### 1. PromptRegistry (Singleton)
The `PromptRegistry` is the central manager for all prompt variants and components. It provides a singleton interface for loading and accessing prompts.
```typescript
class PromptRegistry {
private static instance: PromptRegistry;
private variants: Map<string, PromptVariant> = new Map();
private components: ComponentRegistry = {};
private loaded: boolean = false;
static getInstance(): PromptRegistry {
if (!this.instance) {
this.instance = new PromptRegistry();
}
return this.instance;
}
// Load all prompts and components on initialization
async load(): Promise<void> {
if (this.loaded) return;
await Promise.all([
this.loadVariants(), // Load from variants/ directory
this.loadComponents() // Load from components/ directory
]);
this.loaded = true;
}
/**
* Get prompt by model ID with fallback to generic
*/
async get(context: SystemPromptContext): Promise<string> {
await this.load()
// Try model family fallback (e.g., "claude-4" -> "claude")
const modelFamily = this.getModelFamily(context.providerInfo)
const variant = this.variants.get(modelFamily ?? ModelFamily.GENERIC)
if (!variant) {
throw new Error(
`No prompt variant found for model '${context.providerInfo.model.id}' and no generic fallback available`,
)
}
const builder = new PromptBuilder(variant, context, this.components)
return await builder.build()
}
// Get specific version of a prompt
async getVersion(modelId: string, version: number, context: SystemPromptContext, isNextGenModelFamily?: boolean): Promise<string> {
// Supports next-gen model family prioritization
}
// Get prompt by tag/label
async getByTag(modelId: string, tag?: string, label?: string, context?: SystemPromptContext, isNextGenModelFamily?: boolean): Promise<string> {
// Supports tag and label-based retrieval with next-gen prioritization
}
}
```
### 2. PromptVariant Structure
The `PromptVariant` interface defines the configuration for each model-specific prompt variant:
```typescript
interface PromptVariant {
id: string; // Model family ID (e.g., "next-gen", "generic")
version: number; // Version number
family: ModelFamily; // Model family enum
tags: string[]; // ["production", "beta", "experimental"]
labels: { [key: string]: number }; // {"staging": 2, "prod": 1}
description: string; // Brief description of the variant
// Prompt configuration
config: PromptConfig; // Model-specific config
baseTemplate: string; // Main prompt template with placeholders
componentOrder: SystemPromptSection[]; // Ordered list of components to include
componentOverrides: { [K in SystemPromptSection]?: ConfigOverride }; // Component customizations
placeholders: { [key: string]: string }; // Default placeholder values
// Tool configuration
tools?: ClineDefaultTool[]; // Ordered list of tools to include
toolOverrides?: { [K in ClineDefaultTool]?: ConfigOverride }; // Tool-specific customizations
}
interface PromptConfig {
modelName?: string;
temperature?: number;
maxTokens?: number;
tools?: ClineToolSpec[];
[key: string]: any; // Additional arbitrary config
}
interface ConfigOverride {
template?: string; // Custom template for the component/tool
enabled?: boolean; // Whether the component/tool is enabled
order?: number; // Override the order
}
```
### 3. PromptBuilder
The `PromptBuilder` orchestrates the construction of the final prompt by combining templates, components, and placeholders:
```typescript
class PromptBuilder {
private templateEngine: TemplateEngine;
constructor(
private variant: PromptVariant,
private context: SystemPromptContext,
private components: ComponentRegistry
) {
this.templateEngine = new TemplateEngine();
}
async build(): Promise<string> {
// 1. Build all components in specified order
const componentSections = await this.buildComponents();
// 2. Prepare all placeholder values
const placeholderValues = this.preparePlaceholders(componentSections);
// 3. Resolve template placeholders
const prompt = this.templateEngine.resolve(this.variant.baseTemplate, placeholderValues);
// 4. Apply final post-processing
return this.postProcess(prompt);
}
private async buildComponents(): Promise<Record<string, string>> {
const sections: Record<string, string> = {};
// Process components sequentially to maintain order
for (const componentId of this.variant.componentOrder) {
const componentFn = this.components[componentId];
if (!componentFn) {
console.warn(`Warning: Component '${componentId}' not found`);
continue;
}
try {
const result = await componentFn(this.variant, this.context);
if (result?.trim()) {
sections[componentId] = result;
}
} catch (error) {
console.warn(`Warning: Failed to build component '${componentId}':`, error);
}
}
return sections;
}
private preparePlaceholders(componentSections: Record<string, string>): Record<string, unknown> {
const placeholders: Record<string, unknown> = {};
// Add variant placeholders
Object.assign(placeholders, this.variant.placeholders);
// Add standard system placeholders
placeholders[STANDARD_PLACEHOLDERS.CWD] = this.context.cwd || process.cwd();
placeholders[STANDARD_PLACEHOLDERS.SUPPORTS_BROWSER] = this.context.supportsBrowserUse || false;
placeholders[STANDARD_PLACEHOLDERS.MODEL_FAMILY] = this.variant.family;
placeholders[STANDARD_PLACEHOLDERS.CURRENT_DATE] = new Date().toISOString().split("T")[0];
// Add all component sections
Object.assign(placeholders, componentSections);
// Add runtime placeholders with highest priority
const runtimePlaceholders = (this.context as any).runtimePlaceholders;
if (runtimePlaceholders) {
Object.assign(placeholders, runtimePlaceholders);
}
return placeholders;
}
private postProcess(prompt: string): string {
if (!prompt) return "";
// Combine multiple regex operations for better performance
return prompt
.replace(/\n\s*\n\s*\n/g, "\n\n") // Remove multiple consecutive empty lines
.trim() // Remove leading/trailing whitespace
.replace(/====+\s*$/, "") // Remove trailing ==== after trim
.replace(/\n====+\s*\n+\s*====+\n/g, "\n====\n") // Remove empty sections between separators
.replace(/====\n([^\n])/g, "====\n\n$1") // Ensure proper section separation
.replace(/([^\n])\n====/g, "$1\n\n====");
}
}
```
### 4. Template System
The template system uses `[PLACEHOLDER]` syntax for dynamic content injection:
```typescript
class TemplateEngine {
resolve(template: string, placeholders: Record<string, unknown>): string {
return template.replace(/\{\{([^}]+)\}\}/g, (match, key) => {
const trimmedKey = key.trim();
// Support nested object access using dot notation
const value = this.getNestedValue(placeholders, trimmedKey);
if (value !== undefined && value !== null) {
return typeof value === "string" ? value : JSON.stringify(value);
}
// Keep placeholder if not found (allows for partial resolution)
return match;
});
}
extractPlaceholders(template: string): string[] {
const placeholders: string[] = [];
const regex = /\{\{([^}]+)\}\}/g;
let match: RegExpExecArray | null = null;
match = regex.exec(template);
while (match !== null) {
const placeholder = match[1].trim();
if (!placeholders.includes(placeholder)) {
placeholders.push(placeholder);
}
match = regex.exec(template);
}
return placeholders;
}
}
```
**Base Template Example:**
```markdown
You are Cline, a highly skilled software engineer...
====
[TOOL_USE_SECTION]
====
[MCP_SECTION]
====
[USER_INSTRUCTIONS_SECTION]
====
[SYSTEM_INFO_SECTION]
====
[TODO_SECTION]
```
### 5. Component System
Components are reusable functions that generate specific sections of the prompt:
```typescript
type ComponentFunction = (
variant: PromptVariant,
context: SystemPromptContext
) => Promise<string | undefined>;
// Example component
export async function getSystemInfo(
variant: PromptVariant,
context: SystemPromptContext,
): Promise<string> {
const info = await getSystemEnv();
// Support component overrides
const template = variant.componentOverrides?.SYSTEM_INFO_SECTION?.template || `
Operating System: [os]
Default Shell: [shell]
Home Directory: [homeDir]
Current Working Directory: [workingDir]
`;
return new TemplateEngine().resolve(template, {
os: info.os,
shell: info.shell,
homeDir: info.homeDir,
workingDir: info.workingDir
});
}
```
### 6. Tool System
Tools are managed through the `ClineToolSet` and can be configured per variant:
```typescript
class ClineToolSet {
private static variants: Map<ModelFamily, Set<ClineToolSet>> = new Map();
static register(config: ClineToolSpec): ClineToolSet {
return new ClineToolSet(config.id, config);
}
static getTools(variant: ModelFamily): ClineToolSet[] {
const toolsSet = ClineToolSet.variants.get(variant) || new Set();
const defaultSet = ClineToolSet.variants.get(ModelFamily.GENERIC) || new Set();
return toolsSet ? Array.from(toolsSet) : Array.from(defaultSet);
}
}
// Tool generation in PromptBuilder
public static async getToolsPrompts(variant: PromptVariant, context: SystemPromptContext) {
const tools = ClineToolSet.getTools(variant.family);
// Filter and sort tools based on variant configuration
const enabledTools = tools.filter((tool) =>
!tool.config.contextRequirements || tool.config.contextRequirements(context)
);
let sortedEnabledTools = enabledTools;
if (variant?.tools?.length) {
const toolOrderMap = new Map(variant.tools.map((id, index) => [id, index]));
sortedEnabledTools = enabledTools.sort((a, b) => {
const orderA = toolOrderMap.get(a.config.id);
const orderB = toolOrderMap.get(b.config.id);
if (orderA !== undefined && orderB !== undefined) {
return orderA - orderB;
}
if (orderA !== undefined) return -1;
if (orderB !== undefined) return 1;
return a.config.id.localeCompare(b.config.id);
});
}
const ids = sortedEnabledTools.map((tool) => tool.config.id);
return Promise.all(sortedEnabledTools.map((tool) => PromptBuilder.tool(tool.config, ids)));
}
```
## Configuration Examples
### Basic Variant Configuration (Using Builder Pattern)
```typescript
// variants/generic/config.ts
import { ModelFamily } from "@/shared/prompts";
import { ClineDefaultTool } from "@/shared/tools";
import { SystemPromptSection } from "../../templates/placeholders";
import { validateVariant } from "../../validation/VariantValidator";
import { createVariant } from "../builder";
import { baseTemplate } from "./template";
// Type-safe variant configuration using the builder pattern
export const config = createVariant(ModelFamily.GENERIC)
.description("The fallback prompt for generic use cases and models.")
.version(1)
.tags("fallback", "stable")
.labels({
stable: 1,
fallback: 1,
})
.template(baseTemplate)
.components(
SystemPromptSection.AGENT_ROLE,
SystemPromptSection.TOOL_USE,
SystemPromptSection.MCP,
SystemPromptSection.EDITING_FILES,
SystemPromptSection.ACT_VS_PLAN,
SystemPromptSection.TODO,
SystemPromptSection.CAPABILITIES,
SystemPromptSection.RULES,
SystemPromptSection.SYSTEM_INFO,
SystemPromptSection.OBJECTIVE,
SystemPromptSection.USER_INSTRUCTIONS,
)
.tools(
ClineDefaultTool.BASH,
ClineDefaultTool.FILE_READ,
ClineDefaultTool.FILE_NEW,
ClineDefaultTool.FILE_EDIT,
ClineDefaultTool.SEARCH,
ClineDefaultTool.LIST_FILES,
ClineDefaultTool.LIST_CODE_DEF,
ClineDefaultTool.BROWSER,
ClineDefaultTool.MCP_USE,
ClineDefaultTool.MCP_ACCESS,
ClineDefaultTool.ASK,
ClineDefaultTool.ATTEMPT,
ClineDefaultTool.NEW_TASK,
ClineDefaultTool.PLAN_MODE,
ClineDefaultTool.MCP_DOCS,
ClineDefaultTool.TODO,
)
.placeholders({
MODEL_FAMILY: "generic",
})
.config({})
.build();
// Compile-time validation
const validationResult = validateVariant({ ...config, id: "generic" }, { strict: true });
if (!validationResult.isValid) {
console.error("Generic variant configuration validation failed:", validationResult.errors);
throw new Error(`Invalid generic variant configuration: ${validationResult.errors.join(", ")}`);
}
// Export type information for better IDE support
export type GenericVariantConfig = typeof config;
```
### Advanced Variant with Overrides (Using Builder Pattern)
```typescript
// variants/next-gen/config.ts
import { ModelFamily } from "@/shared/prompts";
import { ClineDefaultTool } from "@/shared/tools";
import { SystemPromptSection } from "../../templates/placeholders";
import { validateVariant } from "../../validation/VariantValidator";
import { createVariant } from "../builder";
import { baseTemplate, rules_template } from "./template";
// Type-safe variant configuration using the builder pattern
export const config = createVariant(ModelFamily.NEXT_GEN)
.description("Prompt tailored to newer frontier models with smarter agentic capabilities.")
.version(1)
.tags("next-gen", "advanced", "production")
.labels({
stable: 1,
production: 1,
advanced: 1,
})
.template(baseTemplate)
.components(
SystemPromptSection.AGENT_ROLE,
SystemPromptSection.TOOL_USE,
SystemPromptSection.MCP,
SystemPromptSection.EDITING_FILES,
SystemPromptSection.ACT_VS_PLAN,
SystemPromptSection.TODO,
SystemPromptSection.CAPABILITIES,
SystemPromptSection.FEEDBACK, // Additional component for next-gen
SystemPromptSection.RULES,
SystemPromptSection.SYSTEM_INFO,
SystemPromptSection.OBJECTIVE,
SystemPromptSection.USER_INSTRUCTIONS,
)
.tools(
ClineDefaultTool.BASH,
ClineDefaultTool.FILE_READ,
ClineDefaultTool.FILE_NEW,
ClineDefaultTool.FILE_EDIT,
ClineDefaultTool.SEARCH,
ClineDefaultTool.LIST_FILES,
ClineDefaultTool.LIST_CODE_DEF,
ClineDefaultTool.BROWSER,
ClineDefaultTool.WEB_FETCH, // Additional tool for next-gen
ClineDefaultTool.MCP_USE,
ClineDefaultTool.MCP_ACCESS,
ClineDefaultTool.ASK,
ClineDefaultTool.ATTEMPT,
ClineDefaultTool.NEW_TASK,
ClineDefaultTool.PLAN_MODE,
ClineDefaultTool.MCP_DOCS,
ClineDefaultTool.TODO,
)
.placeholders({
MODEL_FAMILY: ModelFamily.NEXT_GEN,
})
.config({})
// Override the RULES component with custom template
.overrideComponent(SystemPromptSection.RULES, {
template: rules_template,
})
.build();
// Compile-time validation
const validationResult = validateVariant({ ...config, id: "next-gen" }, { strict: true });
if (!validationResult.isValid) {
console.error("Next-gen variant configuration validation failed:", validationResult.errors);
throw new Error(`Invalid next-gen variant configuration: ${validationResult.errors.join(", ")}`);
}
// Export type information for better IDE support
export type NextGenVariantConfig = typeof config;
```
### Compact Variant with Component Overrides
```typescript
// variants/xs/config.ts
import { ModelFamily } from "@/shared/prompts";
import { ClineDefaultTool } from "@/shared/tools";
import { SystemPromptSection } from "../../templates/placeholders";
import { validateVariant } from "../../validation/VariantValidator";
import { createVariant } from "../builder";
import { xsComponentOverrides } from "./overrides";
import { baseTemplate } from "./template";
— [truncated; see full source: https://github.com/cline/cline]Running prompts needs a free account.
Sign in and we'll stream the response from GPT-5 right here — no config needed for the platform models.
The system prompt architecture provides a modular, composable system for building AI assistant prompts. It supports multiple model variants, dynamic component composition, flexible tool configuration, and template-based prompt generation.
# System Prompt Architecture
## Overview
The system prompt architecture provides a modular, composable system for building AI assistant prompts. It supports multiple model variants, dynamic component composition, flexible tool configuration, and template-based prompt generation.
## Developer
To generate snapshots for each variants added to the unit test in [src/core/prompts/system-prompt/__tests__/integration.test.ts](./__tests__/integration.test.ts):
```sh
npm run test:unit
```
## Directory Structure
```
src/core/prompts/system-prompt/
├── registry/
│ ├── ClineToolSet.ts # Tool set management & registry
│ ├── PromptRegistry.ts # Singleton registry for loading/managing prompts
│ ├── PromptBuilder.ts # Builds final prompts with template resolution
│ └── utils.ts # Model family detection utilities
├── components/ # Reusable prompt components
│ ├── agent_role.ts # Agent role and identity section
│ ├── system_info.ts # System information section
│ ├── mcp.ts # MCP servers section
│ ├── todo.ts # Todo management section
│ ├── user_instructions.ts # User custom instructions
│ ├── tool_use.ts # Tool usage instructions
│ ├── editing_files.ts # File editing guidelines
│ ├── capabilities.ts # Agent capabilities section
│ ├── rules.ts # Behavioral rules section
│ ├── objective.ts # Task objective section
│ ├── act_vs_plan.ts # Action vs planning mode
│ ├── feedback.ts # Feedback and improvement section
│ └── index.ts # Component registry
├── templates/ # Template engine and placeholders
│ ├── TemplateEngine.ts # {{placeholder}} resolution engine
│ └── placeholders.ts # Standard placeholder definitions
├── tools/ # Individual tool definitions
│ ├── spec.ts # Tool specification interface
│ ├── register.ts # Tool registration system
│ ├── index.ts # Tool exports
│ └── [tool-name].ts # Individual tool implementations
├── variants/ # Model-specific prompt variants
│ ├── generic/
│ │ ├── config.ts # Generic fallback configuration
│ │ └── template.ts # Base prompt template
│ ├── next-gen/
│ │ ├── config.ts # Next-gen model configuration
│ │ └── template.ts # Advanced model template
│ ├── xs/
│ │ ├── config.ts # Small model configuration
│ │ └── template.ts # Optimized template
│ └── index.ts # Variant registry exports
├── types.ts # Core type definitions
└── README.md # This documentation
```
## Core Components
### 1. PromptRegistry (Singleton)
The `PromptRegistry` is the central manager for all prompt variants and components. It provides a singleton interface for loading and accessing prompts.
```typescript
class PromptRegistry {
private static instance: PromptRegistry;
private variants: Map<string, PromptVariant> = new Map();
private components: ComponentRegistry = {};
private loaded: boolean = false;
static getInstance(): PromptRegistry {
if (!this.instance) {
this.instance = new PromptRegistry();
}
return this.instance;
}
// Load all prompts and components on initialization
async load(): Promise<void> {
if (this.loaded) return;
await Promise.all([
this.loadVariants(), // Load from variants/ directory
this.loadComponents() // Load from components/ directory
]);
this.loaded = true;
}
/**
* Get prompt by model ID with fallback to generic
*/
async get(context: SystemPromptContext): Promise<string> {
await this.load()
// Try model family fallback (e.g., "claude-4" -> "claude")
const modelFamily = this.getModelFamily(context.providerInfo)
const variant = this.variants.get(modelFamily ?? ModelFamily.GENERIC)
if (!variant) {
throw new Error(
`No prompt variant found for model '${context.providerInfo.model.id}' and no generic fallback available`,
)
}
const builder = new PromptBuilder(variant, context, this.components)
return await builder.build()
}
// Get specific version of a prompt
async getVersion(modelId: string, version: number, context: SystemPromptContext, isNextGenModelFamily?: boolean): Promise<string> {
// Supports next-gen model family prioritization
}
// Get prompt by tag/label
async getByTag(modelId: string, tag?: string, label?: string, context?: SystemPromptContext, isNextGenModelFamily?: boolean): Promise<string> {
// Supports tag and label-based retrieval with next-gen prioritization
}
}
```
### 2. PromptVariant Structure
The `PromptVariant` interface defines the configuration for each model-specific prompt variant:
```typescript
interface PromptVariant {
id: string; // Model family ID (e.g., "next-gen", "generic")
version: number; // Version number
family: ModelFamily; // Model family enum
tags: string[]; // ["production", "beta", "experimental"]
labels: { [key: string]: number }; // {"staging": 2, "prod": 1}
description: string; // Brief description of the variant
// Prompt configuration
config: PromptConfig; // Model-specific config
baseTemplate: string; // Main prompt template with placeholders
componentOrder: SystemPromptSection[]; // Ordered list of components to include
componentOverrides: { [K in SystemPromptSection]?: ConfigOverride }; // Component customizations
placeholders: { [key: string]: string }; // Default placeholder values
// Tool configuration
tools?: ClineDefaultTool[]; // Ordered list of tools to include
toolOverrides?: { [K in ClineDefaultTool]?: ConfigOverride }; // Tool-specific customizations
}
interface PromptConfig {
modelName?: string;
temperature?: number;
maxTokens?: number;
tools?: ClineToolSpec[];
[key: string]: any; // Additional arbitrary config
}
interface ConfigOverride {
template?: string; // Custom template for the component/tool
enabled?: boolean; // Whether the component/tool is enabled
order?: number; // Override the order
}
```
### 3. PromptBuilder
The `PromptBuilder` orchestrates the construction of the final prompt by combining templates, components, and placeholders:
```typescript
class PromptBuilder {
private templateEngine: TemplateEngine;
constructor(
private variant: PromptVariant,
private context: SystemPromptContext,
private components: ComponentRegistry
) {
this.templateEngine = new TemplateEngine();
}
async build(): Promise<string> {
// 1. Build all components in specified order
const componentSections = await this.buildComponents();
// 2. Prepare all placeholder values
const placeholderValues = this.preparePlaceholders(componentSections);
// 3. Resolve template placeholders
const prompt = this.templateEngine.resolve(this.variant.baseTemplate, placeholderValues);
// 4. Apply final post-processing
return this.postProcess(prompt);
}
private async buildComponents(): Promise<Record<string, string>> {
const sections: Record<string, string> = {};
// Process components sequentially to maintain order
for (const componentId of this.variant.componentOrder) {
const componentFn = this.components[componentId];
if (!componentFn) {
console.warn(`Warning: Component '${componentId}' not found`);
continue;
}
try {
const result = await componentFn(this.variant, this.context);
if (result?.trim()) {
sections[componentId] = result;
}
} catch (error) {
console.warn(`Warning: Failed to build component '${componentId}':`, error);
}
}
return sections;
}
private preparePlaceholders(componentSections: Record<string, string>): Record<string, unknown> {
const placeholders: Record<string, unknown> = {};
// Add variant placeholders
Object.assign(placeholders, this.variant.placeholders);
// Add standard system placeholders
placeholders[STANDARD_PLACEHOLDERS.CWD] = this.context.cwd || process.cwd();
placeholders[STANDARD_PLACEHOLDERS.SUPPORTS_BROWSER] = this.context.supportsBrowserUse || false;
placeholders[STANDARD_PLACEHOLDERS.MODEL_FAMILY] = this.variant.family;
placeholders[STANDARD_PLACEHOLDERS.CURRENT_DATE] = new Date().toISOString().split("T")[0];
// Add all component sections
Object.assign(placeholders, componentSections);
// Add runtime placeholders with highest priority
const runtimePlaceholders = (this.context as any).runtimePlaceholders;
if (runtimePlaceholders) {
Object.assign(placeholders, runtimePlaceholders);
}
return placeholders;
}
private postProcess(prompt: string): string {
if (!prompt) return "";
// Combine multiple regex operations for better performance
return prompt
.replace(/\n\s*\n\s*\n/g, "\n\n") // Remove multiple consecutive empty lines
.trim() // Remove leading/trailing whitespace
.replace(/====+\s*$/, "") // Remove trailing ==== after trim
.replace(/\n====+\s*\n+\s*====+\n/g, "\n====\n") // Remove empty sections between separators
.replace(/====\n([^\n])/g, "====\n\n$1") // Ensure proper section separation
.replace(/([^\n])\n====/g, "$1\n\n====");
}
}
```
### 4. Template System
The template system uses `{{PLACEHOLDER}}` syntax for dynamic content injection:
```typescript
class TemplateEngine {
resolve(template: string, placeholders: Record<string, unknown>): string {
return template.replace(/\{\{([^}]+)\}\}/g, (match, key) => {
const trimmedKey = key.trim();
// Support nested object access using dot notation
const value = this.getNestedValue(placeholders, trimmedKey);
if (value !== undefined && value !== null) {
return typeof value === "string" ? value : JSON.stringify(value);
}
// Keep placeholder if not found (allows for partial resolution)
return match;
});
}
extractPlaceholders(template: string): string[] {
const placeholders: string[] = [];
const regex = /\{\{([^}]+)\}\}/g;
let match: RegExpExecArray | null = null;
match = regex.exec(template);
while (match !== null) {
const placeholder = match[1].trim();
if (!placeholders.includes(placeholder)) {
placeholders.push(placeholder);
}
match = regex.exec(template);
}
return placeholders;
}
}
```
**Base Template Example:**
```markdown
You are Cline, a highly skilled software engineer...
====
{{TOOL_USE_SECTION}}
====
{{MCP_SECTION}}
====
{{USER_INSTRUCTIONS_SECTION}}
====
{{SYSTEM_INFO_SECTION}}
====
{{TODO_SECTION}}
```
### 5. Component System
Components are reusable functions that generate specific sections of the prompt:
```typescript
type ComponentFunction = (
variant: PromptVariant,
context: SystemPromptContext
) => Promise<string | undefined>;
// Example component
export async function getSystemInfo(
variant: PromptVariant,
context: SystemPromptContext,
): Promise<string> {
const info = await getSystemEnv();
// Support component overrides
const template = variant.componentOverrides?.SYSTEM_INFO_SECTION?.template || `
Operating System: {{os}}
Default Shell: {{shell}}
Home Directory: {{homeDir}}
Current Working Directory: {{workingDir}}
`;
return new TemplateEngine().resolve(template, {
os: info.os,
shell: info.shell,
homeDir: info.homeDir,
workingDir: info.workingDir
});
}
```
### 6. Tool System
Tools are managed through the `ClineToolSet` and can be configured per variant:
```typescript
class ClineToolSet {
private static variants: Map<ModelFamily, Set<ClineToolSet>> = new Map();
static register(config: ClineToolSpec): ClineToolSet {
return new ClineToolSet(config.id, config);
}
static getTools(variant: ModelFamily): ClineToolSet[] {
const toolsSet = ClineToolSet.variants.get(variant) || new Set();
const defaultSet = ClineToolSet.variants.get(ModelFamily.GENERIC) || new Set();
return toolsSet ? Array.from(toolsSet) : Array.from(defaultSet);
}
}
// Tool generation in PromptBuilder
public static async getToolsPrompts(variant: PromptVariant, context: SystemPromptContext) {
const tools = ClineToolSet.getTools(variant.family);
// Filter and sort tools based on variant configuration
const enabledTools = tools.filter((tool) =>
!tool.config.contextRequirements || tool.config.contextRequirements(context)
);
let sortedEnabledTools = enabledTools;
if (variant?.tools?.length) {
const toolOrderMap = new Map(variant.tools.map((id, index) => [id, index]));
sortedEnabledTools = enabledTools.sort((a, b) => {
const orderA = toolOrderMap.get(a.config.id);
const orderB = toolOrderMap.get(b.config.id);
if (orderA !== undefined && orderB !== undefined) {
return orderA - orderB;
}
if (orderA !== undefined) return -1;
if (orderB !== undefined) return 1;
return a.config.id.localeCompare(b.config.id);
});
}
const ids = sortedEnabledTools.map((tool) => tool.config.id);
return Promise.all(sortedEnabledTools.map((tool) => PromptBuilder.tool(tool.config, ids)));
}
```
## Configuration Examples
### Basic Variant Configuration (Using Builder Pattern)
```typescript
// variants/generic/config.ts
import { ModelFamily } from "@/shared/prompts";
import { ClineDefaultTool } from "@/shared/tools";
import { SystemPromptSection } from "../../templates/placeholders";
import { validateVariant } from "../../validation/VariantValidator";
import { createVariant } from "../builder";
import { baseTemplate } from "./template";
// Type-safe variant configuration using the builder pattern
export const config = createVariant(ModelFamily.GENERIC)
.description("The fallback prompt for generic use cases and models.")
.version(1)
.tags("fallback", "stable")
.labels({
stable: 1,
fallback: 1,
})
.template(baseTemplate)
.components(
SystemPromptSection.AGENT_ROLE,
SystemPromptSection.TOOL_USE,
SystemPromptSection.MCP,
SystemPromptSection.EDITING_FILES,
SystemPromptSection.ACT_VS_PLAN,
SystemPromptSection.TODO,
SystemPromptSection.CAPABILITIES,
SystemPromptSection.RULES,
SystemPromptSection.SYSTEM_INFO,
SystemPromptSection.OBJECTIVE,
SystemPromptSection.USER_INSTRUCTIONS,
)
.tools(
ClineDefaultTool.BASH,
ClineDefaultTool.FILE_READ,
ClineDefaultTool.FILE_NEW,
ClineDefaultTool.FILE_EDIT,
ClineDefaultTool.SEARCH,
ClineDefaultTool.LIST_FILES,
ClineDefaultTool.LIST_CODE_DEF,
ClineDefaultTool.BROWSER,
ClineDefaultTool.MCP_USE,
ClineDefaultTool.MCP_ACCESS,
ClineDefaultTool.ASK,
ClineDefaultTool.ATTEMPT,
ClineDefaultTool.NEW_TASK,
ClineDefaultTool.PLAN_MODE,
ClineDefaultTool.MCP_DOCS,
ClineDefaultTool.TODO,
)
.placeholders({
MODEL_FAMILY: "generic",
})
.config({})
.build();
// Compile-time validation
const validationResult = validateVariant({ ...config, id: "generic" }, { strict: true });
if (!validationResult.isValid) {
console.error("Generic variant configuration validation failed:", validationResult.errors);
throw new Error(`Invalid generic variant configuration: ${validationResult.errors.join(", ")}`);
}
// Export type information for better IDE support
export type GenericVariantConfig = typeof config;
```
### Advanced Variant with Overrides (Using Builder Pattern)
```typescript
// variants/next-gen/config.ts
import { ModelFamily } from "@/shared/prompts";
import { ClineDefaultTool } from "@/shared/tools";
import { SystemPromptSection } from "../../templates/placeholders";
import { validateVariant } from "../../validation/VariantValidator";
import { createVariant } from "../builder";
import { baseTemplate, rules_template } from "./template";
// Type-safe variant configuration using the builder pattern
export const config = createVariant(ModelFamily.NEXT_GEN)
.description("Prompt tailored to newer frontier models with smarter agentic capabilities.")
.version(1)
.tags("next-gen", "advanced", "production")
.labels({
stable: 1,
production: 1,
advanced: 1,
})
.template(baseTemplate)
.components(
SystemPromptSection.AGENT_ROLE,
SystemPromptSection.TOOL_USE,
SystemPromptSection.MCP,
SystemPromptSection.EDITING_FILES,
SystemPromptSection.ACT_VS_PLAN,
SystemPromptSection.TODO,
SystemPromptSection.CAPABILITIES,
SystemPromptSection.FEEDBACK, // Additional component for next-gen
SystemPromptSection.RULES,
SystemPromptSection.SYSTEM_INFO,
SystemPromptSection.OBJECTIVE,
SystemPromptSection.USER_INSTRUCTIONS,
)
.tools(
ClineDefaultTool.BASH,
ClineDefaultTool.FILE_READ,
ClineDefaultTool.FILE_NEW,
ClineDefaultTool.FILE_EDIT,
ClineDefaultTool.SEARCH,
ClineDefaultTool.LIST_FILES,
ClineDefaultTool.LIST_CODE_DEF,
ClineDefaultTool.BROWSER,
ClineDefaultTool.WEB_FETCH, // Additional tool for next-gen
ClineDefaultTool.MCP_USE,
ClineDefaultTool.MCP_ACCESS,
ClineDefaultTool.ASK,
ClineDefaultTool.ATTEMPT,
ClineDefaultTool.NEW_TASK,
ClineDefaultTool.PLAN_MODE,
ClineDefaultTool.MCP_DOCS,
ClineDefaultTool.TODO,
)
.placeholders({
MODEL_FAMILY: ModelFamily.NEXT_GEN,
})
.config({})
// Override the RULES component with custom template
.overrideComponent(SystemPromptSection.RULES, {
template: rules_template,
})
.build();
// Compile-time validation
const validationResult = validateVariant({ ...config, id: "next-gen" }, { strict: true });
if (!validationResult.isValid) {
console.error("Next-gen variant configuration validation failed:", validationResult.errors);
throw new Error(`Invalid next-gen variant configuration: ${validationResult.errors.join(", ")}`);
}
// Export type information for better IDE support
export type NextGenVariantConfig = typeof config;
```
### Compact Variant with Component Overrides
```typescript
// variants/xs/config.ts
import { ModelFamily } from "@/shared/prompts";
import { ClineDefaultTool } from "@/shared/tools";
import { SystemPromptSection } from "../../templates/placeholders";
import { validateVariant } from "../../validation/VariantValidator";
import { createVariant } from "../builder";
import { xsComponentOverrides } from "./overrides";
import { baseTemplate } from "./template";
— [truncated; see full source: https://github.com/cline/cline]{{placeholder}}{{tool_use_section}}{{mcp_section}}{{user_instructions_section}}{{system_info_section}}{{todo_section}}{{os}}{{shell}}{{homedir}}{{workingdir}}{{componentid}}