Skip to main content

Overview

LuaAgent is the recommended way to configure your AI agent in modern lua-cli. It provides a single, intuitive configuration object that combines skills, webhooks, jobs, and message processors.
import { LuaAgent } from 'lua-cli';

export const agent = new LuaAgent({
  name: 'my-agent',
  persona: 'You are a helpful assistant...',
  skills: [skill1, skill2]
});
LuaAgent replaces the need to export individual skills, webhooks, and jobs separately.

Why LuaAgent?

Single Source of Truth

All agent components in one configuration object

Auto-Sync

CLI auto-manages lua.skill.yaml (do not edit manually)

Better IDE Support

Improved autocomplete and type safety

Clear Organization

Organized, readable agent configuration

Constructor

new LuaAgent(config)

Creates a new agent configuration.
config
LuaAgentConfig
required
Agent configuration object

Configuration Parameters

Required Fields

name
string
required
Agent identifier used for organization and loggingExamples: 'customer-support-agent', 'sales-assistant'
persona
string | { base?: string; voice?: string; text?: string }
required
Defines the agent’s personality, behavior, tone, and capabilitiesString form (recommended):
  • Who the agent is
  • What role they play
  • How they should communicate
  • What they can and cannot do
  • Any specific behaviors or rules
Object form (channel-aware): Only use when you need measurably different behavior on voice vs text channels.
  • base — Always rendered, on every channel
  • voice — Appended to base on voice channels, ignored on text
  • text — Appended to base on text channels (web, WhatsApp, SMS), ignored on voice
See Channel-aware Prompts for details.

Optional Fields

skills
LuaSkill[]
Array of skills (tool collections) the agent can useDefault: []
webhooks
LuaWebhook[]
HTTP endpoints that can receive external eventsDefault: []
jobs
LuaJob[]
Scheduled tasks that run automaticallyDefault: []
preProcessors
PreProcessor[]
Functions that process messages before they reach the agentDefault: []
postProcessors
PostProcessor[]
Functions that process agent responses before sending to usersDefault: []
mcpServers
LuaMCPServer[]
MCP (Model Context Protocol) servers providing external toolsDefault: []See: LuaMCPServer API
model
string | ((request: LuaRequest) => string | Promise<string>)
The LLM your agent uses. Either a static 'provider/model' string or a resolver function that selects the model dynamically per request.Format: 'provider/model' — e.g. 'google/gemini-2.5-flash', 'openai/gpt-4o'Default: 'google/gemini-2.5-flash'
Lua manages the API credentials — you don’t need to configure any API keys. Support for user-provided API keys is coming in a future release.
Static model:
model: 'openai/gpt-4o'
Dynamic resolver — receives the full request with all platform APIs available (User, Baskets, Products, etc.):
model: async (request) => {
  const user = await User.get();
  return user.data?.isPremium ? 'openai/gpt-4o' : 'google/gemini-2.5-flash';
}
See: Model Selection
modelSettings
AgentModelSettings
Per-call sampling settings forwarded to the model on every chat turn. Set them once on the agent instead of overriding them in every skill via AI.generate({ temperature }). Undefined leaves provider defaults in place.
import { LuaAgent, type AgentModelSettings } from 'lua-cli';

export const agent = new LuaAgent({
  name: 'role-scorer',
  persona: '...',
  modelSettings: {
    temperature: 0.2,
    maxOutputTokens: 4096,
  },
  skills: [scoreRoleSkill],
});
Supported fields:
FieldTypeRange / Notes
temperaturenumber02 (provider-dependent; typical for OpenAI / Anthropic)
topPnumber01. Set either temperature or topP, not both.
topKnumberTop-K sampling (advanced)
maxOutputTokensnumberMaximum tokens to generate
presencePenaltynumber-22 (OpenAI; not all providers support)
frequencyPenaltynumber-22 (OpenAI; not all providers support)
stopSequencesstring[]Generation halts when the model emits one
seednumberRandom seed for deterministic sampling (provider support varies)
Obviously-broken values (non-finite numbers, temperature outside 0..2, topP outside 0..1, non-positive maxOutputTokens, non-string stopSequences) are rejected at construction time. Provider-specific range checks are deferred to the provider.

Basic Example

import { LuaAgent, LuaSkill } from 'lua-cli';
import GetWeatherTool from './tools/GetWeatherTool';

const weatherSkill = new LuaSkill({
  name: 'weather-skill',
  description: 'Weather information',
  context: 'Use these tools to get weather data',
  tools: [new GetWeatherTool()]
});

export const agent = new LuaAgent({
  name: 'weather-assistant',
  persona: 'You are a friendly weather assistant. Provide weather information when asked.',
  skills: [weatherSkill]
});

Complete Example

import { 
  LuaAgent, 
  LuaSkill, 
  LuaWebhook, 
  LuaJob,
  LuaMCPServer,
  PreProcessor,
  PostProcessor
} from 'lua-cli';

// Import your components
import { customerSupportSkill } from './skills/customer-support';
import { productSkill } from './skills/products';
import { orderSkill } from './skills/orders';
import paymentWebhook from './webhooks/payment';
import orderWebhook from './webhooks/order';
import dailyReportJob from './jobs/daily-report';
import cleanupJob from './jobs/cleanup';
import profanityFilter from './preprocessors/profanity-filter';
import addDisclaimer from './postprocessors/disclaimer';
import filesystemServer from './mcp/filesystem';

export const agent = new LuaAgent({
  name: 'ecommerce-assistant',
  
  persona: `You are Emma, a helpful e-commerce assistant for Acme Store.
  
Your role:
- Help customers find products
- Assist with orders and cart management
- Answer product questions
- Process returns and exchanges

Communication style:
- Friendly and professional
- Patient and understanding
- Proactive with suggestions
- Clear and concise

Capabilities:
- Search product catalog
- Manage shopping carts
- Track orders
- Process payments
- Answer product questions

Limitations:
- Cannot ship orders manually
- Cannot modify pricing (suggest contacting manager)
- Cannot issue refunds over $100 (requires manager approval)
`,

  skills: [
    customerSupportSkill,
    productSkill,
    orderSkill
  ],

  webhooks: [
    paymentWebhook,
    orderWebhook
  ],

  jobs: [
    dailyReportJob,
    cleanupJob
  ],

  preProcessors: [
    profanityFilter
  ],

  postProcessors: [
    addDisclaimer
  ],

  mcpServers: [
    filesystemServer
  ]
});

Persona Best Practices

✅ Good Persona

persona: `You are Dr. Smith, a medical information assistant.

Role: Provide general health information and wellness tips.

Guidelines:
- Always clarify you're not a licensed doctor
- Recommend seeing professionals for serious concerns
- Use clear, non-technical language
- Be empathetic and supportive

Tone: Professional, caring, informative`

❌ Bad Persona

// Too vague
persona: `You are helpful`

// Too robotic
persona: `I am an AI assistant that answers questions.`

// Missing boundaries
persona: `You can do anything the user asks.`

Persona Storage

Persona is stored in your LuaAgent code definition (in src/index.ts). The lua.skill.yaml file is state-only and tracks IDs and versions, not persona content. When you edit persona using lua persona, it updates the persona field in your LuaAgent code directly.

Multiple Skills Example

import { LuaAgent, LuaSkill } from 'lua-cli';

// Organize tools by domain
const weatherSkill = new LuaSkill({
  name: 'weather-skill',
  description: 'Weather tools',
  context: 'Use for weather queries',
  tools: [getWeatherTool, getForecastTool]
});

const calculatorSkill = new LuaSkill({
  name: 'calculator-skill',
  description: 'Math tools',
  context: 'Use for calculations',
  tools: [addTool, multiplyTool, advancedMathTool]
});

const dataSkill = new LuaSkill({
  name: 'data-skill',
  description: 'Data management',
  context: 'Use for storing and retrieving user data',
  tools: [saveDataTool, queryDataTool]
});

export const agent = new LuaAgent({
  name: 'multi-purpose-assistant',
  persona: 'You are a versatile assistant that helps with weather, calculations, and data management.',
  skills: [weatherSkill, calculatorSkill, dataSkill]
});

With All Components

import { LuaAgent } from 'lua-cli';
import { skills } from './skills';
import { webhooks } from './webhooks';
import { jobs } from './jobs';
import { preProcessors } from './preprocessors';
import { postProcessors } from './postprocessors';
import { mcpServers } from './mcp';

export const agent = new LuaAgent({
  name: 'enterprise-assistant',
  
  persona: `You are an enterprise-grade AI assistant.
  - Professional and efficient
  - Data-driven and accurate
  - Proactive with insights
  - Security and privacy conscious`,
  
  skills: skills,
  webhooks: webhooks,
  jobs: jobs,
  preProcessors: preProcessors,
  postProcessors: postProcessors,
  mcpServers: mcpServers
});

Dynamic Configuration

import { LuaAgent } from 'lua-cli';
import { env } from 'lua-cli';

// Load configuration from environment
const agentName = env('AGENT_NAME') || 'default-agent';
const customPersona = env('AGENT_PERSONA') || 'You are a helpful assistant';

// Conditionally add components
const skills = [coreSkill];
if (env('ENABLE_ANALYTICS') === 'true') {
  skills.push(analyticsSkill);
}

export const agent = new LuaAgent({
  name: agentName,
  persona: customPersona,
  skills: skills,
  // Add webhooks only in production
  webhooks: env('NODE_ENV') === 'production' ? productionWebhooks : []
});

Migration from v2.x

Before (v2.x):
// Multiple exports
export const skill1 = new LuaSkill({...});
export const skill2 = new LuaSkill({...});
export const webhook1 = new LuaWebhook({...});
After:
// Single export with LuaAgent
export const agent = new LuaAgent({
  name: 'my-agent',
  persona: '...',
  skills: [skill1, skill2],
  webhooks: [webhook1]
});

LuaSkill

Tool collections

LuaTool

Individual tools

LuaWebhook

HTTP endpoints

LuaJob

Scheduled tasks

LuaMCPServer

External MCP tools

See Also