Skip to main content

Overview

SystemPromptBuilder implements a fluent API pattern for building comprehensive system prompts. It collects configuration for agent identity, capabilities, tools, constraints, communication style, and output formatting. When you call .build(), it generates a structured markdown document that serves as the system prompt for your AI agent.

Constructor

Do not instantiate directly. Use the createPromptBuilder() factory function instead.
import { createPromptBuilder } from "promptsmith-ts";

const builder = createPromptBuilder();

Core Configuration Methods

withIdentity()

Sets the agent’s core identity or purpose.
withIdentity(text: string): this
text
string
required
Description of the agent’s identity. Should be written in second person (“You are…”) or third person (“The assistant is…”).
Example:
builder.withIdentity("You are an expert travel assistant specializing in European destinations");

withCapability()

Adds a single capability to the agent’s skillset.
withCapability(cap: string): this
cap
string
required
A single capability description. Should be action-oriented and specific.
Example:
builder
  .withCapability("Search and analyze research papers")
  .withCapability("Generate literature reviews");

withCapabilities()

Adds multiple capabilities at once.
withCapabilities(caps: string[]): this
caps
string[]
required
An array of capability descriptions. Empty strings are filtered out automatically.
Example:
builder.withCapabilities([
  "Analyze financial data and trends",
  "Calculate investment returns",
  "Provide risk assessments"
]);

Tool Registration Methods

withTool()

Registers a tool that the agent can use.
withTool<T extends ZodType>(def: ExecutableToolDefinition<T>): this
withTool(def: MastraToolDefinition): this
def.name
string
required
Unique identifier for the tool (snake_case recommended)
def.description
string
required
Human-readable description of what the tool does and when to use it
def.schema
ZodType
required
Zod schema defining the tool’s input parameters
def.execute
(args: T) => Promise<unknown> | unknown
Optional execution function for runtime tool usage
Example:
import { z } from "zod";

// With execution logic
builder.withTool({
  name: "get_weather",
  description: "Retrieves current weather for a location",
  schema: z.object({
    location: z.string().describe("City name or ZIP code"),
    units: z.enum(["celsius", "fahrenheit"]).optional()
  }),
  execute: async ({ location, units }) => {
    const response = await fetch(`https://api.weather.com/${location}?units=${units}`);
    return response.json();
  }
});

// Documentation-only tool (no execute function)
builder.withTool({
  name: "search_database",
  description: "Search the knowledge database",
  schema: z.object({
    query: z.string()
  })
});
The withTool() method automatically detects and converts Mastra tools created with createTool() from @mastra/core/tools.

withTools()

Registers multiple tools at once.
withTools(defs: ExecutableToolDefinition[]): this
defs
ExecutableToolDefinition[]
required
An array of tool definitions

withToolIf()

Conditionally registers a tool based on a condition.
withToolIf(condition: boolean, def: ExecutableToolDefinition): this
condition
boolean
required
Boolean condition that determines if the tool is added
def
ExecutableToolDefinition
required
Tool definition to add if condition is true
Example:
const hasDatabase = config.databaseEnabled;

builder.withToolIf(hasDatabase, {
  name: "query_db",
  description: "Query the database",
  schema: z.object({ query: z.string() }),
  execute: async ({ query }) => await db.execute(query)
});

Constraint Methods

withConstraint()

Adds a behavioral constraint or guideline.
withConstraint(type: ConstraintType, rule: string): this
type
'must' | 'must_not' | 'should' | 'should_not'
required
The constraint severity level
rule
string
required
The constraint rule text. Should be clear, specific, and actionable.
Constraint Types:
  • must: Absolute requirements that cannot be violated
  • must_not: Absolute prohibitions
  • should: Strong recommendations to follow when possible
  • should_not: Strong recommendations to avoid
Example:
builder
  .withConstraint("must", "Always verify user authentication before accessing personal data")
  .withConstraint("must_not", "Never store or log sensitive information")
  .withConstraint("should", "Provide concise responses unless detail is requested");

withConstraints()

Adds one or more constraints with the same type.
withConstraints(type: ConstraintType, rules: string | string[]): this
type
ConstraintType
required
The constraint severity level
rules
string | string[]
required
Single rule string or array of rule strings

withConstraintIf()

Conditionally adds a constraint based on a condition.
withConstraintIf(condition: boolean, type: ConstraintType, rule: string): this

Communication & Formatting Methods

withOutput()

Sets the output format guidelines for the agent’s responses.
withOutput(format: string): this
format
string
required
Output format description or template. Can include examples, numbered steps, or structural guidelines.
Example:
builder.withOutput(`
  Use the following structure:
  - Brief overview (2-3 sentences)
  - Bullet points for key information
  - Code examples when relevant
  - Concluding recommendation
`);

withTone()

Sets the communication tone and style.
withTone(tone: string): this
tone
string
required
Description of the desired communication style
Example:
builder.withTone("Be friendly, enthusiastic, and encouraging. Use a conversational tone.");

withFormat()

Sets the output format for the generated prompt.
withFormat(format: PromptFormat): this
format
'markdown' | 'toon' | 'compact'
required
The desired output format
Format Options:
  • markdown: Standard markdown format (default, human-readable)
  • toon: TOON format (Token-Oriented Object Notation) - 30-60% token reduction
  • compact: Minimal whitespace variant of markdown
Example:
builder.withFormat('toon'); // Optimize for token efficiency

Security & Safety Methods

withGuardrails()

Enables standard anti-prompt-injection security guardrails.
withGuardrails(): this
Activates:
  • Input Isolation: Treats all user inputs as untrusted data
  • Role Protection: Prevents identity override attempts
  • Instruction Separation: System instructions take precedence
  • Output Safety: Prevents prompt revelation
Example:
builder
  .withIdentity("You are a customer service assistant")
  .withGuardrails();
Always enable guardrails for production applications where user input cannot be fully trusted or where the agent has access to sensitive operations.

withForbiddenTopics()

Specifies topics that the agent must not discuss.
withForbiddenTopics(topics: string[]): this
topics
string[]
required
Array of topic descriptions that should be off-limits
Example:
builder.withForbiddenTopics([
  "Medical diagnosis or treatment advice",
  "Legal advice or interpretation of laws",
  "Financial investment recommendations"
]);

Context & Learning Methods

withContext()

Provides domain-specific context and background knowledge.
withContext(text: string): this
text
string
required
Contextual information for the agent. Can be multi-line.
Example:
builder.withContext(`
  Our clinic operates Monday-Friday, 9 AM to 5 PM.
  We have three doctors:
  - Dr. Smith specializes in general medicine
  - Dr. Jones specializes in cardiology
  - Dr. Lee specializes in pediatrics
`);

withExamples()

Provides examples of desired agent behavior through few-shot learning.
withExamples(examples: Example[]): this
examples
Example[]
required
Array of example objects showing input-output pairs
Example Type:
type Example = {
  user?: string;        // User input (conversational style)
  assistant?: string;   // Agent response (conversational style)
  input?: string;       // Input (functional style)
  output?: string;      // Output (functional style)
  explanation?: string; // Why this example is good
}
Example:
builder.withExamples([
  {
    user: "What's the weather in Paris?",
    assistant: "I'll check the weather for you. *calls get_weather tool*",
    explanation: "Shows proper tool invocation for weather queries"
  },
  {
    user: "Book me a table for 2 at 7pm",
    assistant: "I'll help you make a reservation. What restaurant would you like?",
    explanation: "Shows how to ask for missing required information"
  }
]);

withErrorHandling()

Defines how the agent should handle uncertainty and errors.
withErrorHandling(instructions: string): this
instructions
string
required
Guidelines for handling uncertainty and errors. Can be multi-line.
Example:
builder.withErrorHandling(`
  Error Handling Guidelines:
  - If a request is ambiguous, ask specific clarifying questions
  - If you lack required information, explicitly list what's needed
  - If uncertain about facts, acknowledge uncertainty rather than guessing
  - For tool errors, explain the issue in user-friendly terms
`);

Advanced Methods

extend()

Creates a new builder instance based on this one.
extend(): SystemPromptBuilder
Returns: A new SystemPromptBuilder instance with copied state Example:
const baseSupport = createPromptBuilder()
  .withIdentity("You are a helpful support assistant")
  .withGuardrails();

const technicalSupport = baseSupport.extend()
  .withIdentity("You are a technical support specialist")
  .withCapability("Debug technical issues");

merge()

Merges another builder’s configuration into this one.
merge(source: SystemPromptBuilder): this
source
SystemPromptBuilder
required
The builder to merge into this one
Merge Rules:
  • Identity: Uses this builder’s identity (not overridden)
  • Capabilities: Combines both lists (removes duplicates)
  • Tools: Combines both lists (throws error if duplicate names)
  • Constraints: Combines both lists
  • Guardrails: Enabled if either has it enabled
Example:
const securityBuilder = createPromptBuilder()
  .withGuardrails()
  .withConstraint("must", "Always verify user identity");

const customerService = createPromptBuilder()
  .withIdentity("You are a customer service assistant")
  .merge(securityBuilder);

validate()

Validates the current builder configuration.
validate(config?: ValidatorConfig): ValidationResult
config
ValidatorConfig
Optional validator configuration to customize validation rules
Returns: ValidationResult object containing validation status and issues Example:
const result = builder.validate();

if (!result.valid) {
  console.error("Validation errors:", result.errors);
}

if (result.warnings.length > 0) {
  console.warn("Warnings:", result.warnings);
}

withValidatorConfig()

Sets the default validator configuration.
withValidatorConfig(config: ValidatorConfig): this

Inspection Methods

getTools()

Returns the list of registered tools.
getTools(): ExecutableToolDefinition[]

getSummary()

Returns a summary of the builder’s current state.
getSummary(): {
  hasIdentity: boolean;
  capabilitiesCount: number;
  toolsCount: number;
  constraintsCount: number;
  constraintsByType: {
    must: number;
    must_not: number;
    should: number;
    should_not: number;
  };
  examplesCount: number;
  hasGuardrails: boolean;
  forbiddenTopicsCount: number;
  hasContext: boolean;
  hasTone: boolean;
  hasOutputFormat: boolean;
  hasErrorHandling: boolean;
  format: PromptFormat;
}

debug()

Outputs detailed debug information to console.
debug(): this
Example:
builder
  .withIdentity("Assistant")
  .withCapability("Answer questions")
  .debug(); // Logs detailed information

Boolean Check Methods

hasTools(): boolean
hasConstraints(): boolean
hasIdentity(): boolean
hasCapabilities(): boolean
hasExamples(): boolean
hasGuardrails(): boolean
hasForbiddenTopics(): boolean

getConstraintsByType()

Returns constraints of a specific type.
getConstraintsByType(type: ConstraintType): Constraint[]

Output Methods

build()

Builds and returns the complete system prompt as a string.
build(format?: PromptFormat): string
format
'markdown' | 'toon' | 'compact'
Optional format override. If not provided, uses the format set via withFormat() (defaults to ‘markdown’)
Returns: Formatted system prompt string ready for use with AI models Example:
const prompt = builder.build();
const toonPrompt = builder.build('toon'); // Override to TOON format

toAiSdk()

Exports a complete AI SDK configuration object.
toAiSdk(): AiSdkConfig
Returns:
{
  system: string;  // The complete system prompt
  tools: Record<string, {
    description: string;
    parameters: ZodType;
    execute?: (args: unknown) => Promise<unknown> | unknown;
  }>;
}
Example:
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";

const response = await generateText({
  model: openai("gpt-4"),
  ...builder.toAiSdk(),
  prompt: "What's the weather in Paris?"
});

toAiSdkTools()

Exports tools in Vercel AI SDK format.
toAiSdkTools(): Record<string, {
  description: string;
  parameters: ZodType;
  execute?: (args: unknown) => Promise<unknown> | unknown;
}>

toMastra()

Exports configuration for Mastra agents.
toMastra(): {
  instructions: string;
  tools: Record<string, {
    id: string;
    description: string;
    inputSchema: ZodType;
    outputSchema?: ZodType;
    execute?: (args: { context: unknown }) => Promise<unknown> | unknown;
  }>;
}
Example:
import { Agent } from "@mastra/core/agent";

const { instructions, tools } = builder.toMastra();

const agent = new Agent({
  name: "weather-agent",
  instructions,
  model: "openai/gpt-4o",
  tools
});

toJSON()

Exports the builder’s configuration as a plain JavaScript object.
toJSON(): object
Example:
const config = builder.toJSON();
fs.writeFileSync('agent-config.json', JSON.stringify(config, null, 2));

Complete Example

import { createPromptBuilder } from "promptsmith-ts";
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";

const builder = createPromptBuilder()
  .withIdentity("You are a professional customer service assistant")
  .withCapabilities([
    "Answer product questions",
    "Process returns and refunds",
    "Track order status"
  ])
  .withTool({
    name: "lookup_order",
    description: "Look up order details by order ID",
    schema: z.object({
      orderId: z.string().describe("The order ID to look up")
    }),
    execute: async ({ orderId }) => {
      return await database.orders.findById(orderId);
    }
  })
  .withConstraint("must", "Always verify customer identity before discussing order details")
  .withConstraint("must_not", "Never process refunds over $500 without manager approval")
  .withTone("Be empathetic, professional, and solution-oriented")
  .withGuardrails()
  .withErrorHandling("If uncertain, ask clarifying questions rather than making assumptions")
  .withFormat('toon'); // Use token-optimized format

// Validate before using
const validation = builder.validate();
if (!validation.valid) {
  console.error("Configuration errors:", validation.errors);
}

// Use with AI SDK
const response = await generateText({
  model: openai("gpt-4"),
  ...builder.toAiSdk(),
  prompt: "I want to return my order #12345"
});

Build docs developers (and LLMs) love