Skip to main content

Build a Task Management Skill

Let’s build a complete skill that manages tasks (create, list, complete, delete).

Step 1: Initialize Project

mkdir task-management-skill
cd task-management-skill
lua init
Follow the prompts to create a new agent.

Step 2: Clean Up Template

Remove unnecessary example files:
rm src/tools/ProductsTool.ts
rm src/tools/BasketTool.ts
rm src/tools/OrderTool.ts
rm src/tools/PaymentTool.ts
rm src/tools/GetWeatherTool.ts

Step 3: Create Task Tool

Create src/tools/TaskTool.ts:
import { LuaTool, Data } from "lua-cli";
import { z } from "zod";

export class CreateTaskTool implements LuaTool {
  name = "create_task";
  description = "Create a new task";
  
  inputSchema = z.object({
    title: z.string().describe("Task title"),
    description: z.string().optional(),
    priority: z.enum(['low', 'medium', 'high']).default('medium'),
    dueDate: z.string().optional()
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    const task = await Data.create('tasks', {
      ...input,
      status: 'pending',
      createdAt: new Date().toISOString()
    }, input.title + ' ' + (input.description || ''));
    
    return {
      taskId: task.id,
      message: `Task "${input.title}" created`
    };
  }
}

export class ListTasksTool implements LuaTool {
  name = "list_tasks";
  description = "List all tasks, optionally filtered by status";
  
  inputSchema = z.object({
    status: z.enum(['pending', 'in_progress', 'completed']).optional()
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    const filter = input.status ? { status: input.status } : {};
    const result = await Data.get('tasks', filter, 1, 50);
    
    return {
      tasks: result.data.map(entry => ({
        id: entry.id,
        ...entry.data
      })),
      count: result.pagination.totalCount
    };
  }
}

export class CompleteTaskTool implements LuaTool {
  name = "complete_task";
  description = "Mark a task as completed";
  
  inputSchema = z.object({
    taskId: z.string()
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    const task = await Data.getEntry('tasks', input.taskId);
    
    await Data.update('tasks', input.taskId, {
      ...task.data,
      status: 'completed',
      completedAt: new Date().toISOString()
    });
    
    return {
      success: true,
      message: `Task "${task.data.title}" marked as completed`
    };
  }
}

export class SearchTasksTool implements LuaTool {
  name = "search_tasks";
  description = "Search tasks by content";
  
  inputSchema = z.object({
    query: z.string()
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    const results = await Data.search('tasks', input.query, 20, 0.6);
    
    return {
      tasks: results.data.map(entry => ({
        id: entry.id,
        ...entry.data,
        relevance: entry.score
      }))
    };
  }
}

Step 4: Create Agent with Skill

Update src/index.ts to use the v3.0.0 LuaAgent pattern:
import { LuaAgent, LuaSkill } from "lua-cli";
import {
  CreateTaskTool,
  ListTasksTool,
  CompleteTaskTool,
  SearchTasksTool
} from "./tools/TaskTool";

// Create the task management skill
const taskSkill = new LuaSkill({
  name: "task-management-skill",
  description: "Manage tasks and to-do lists with creation, listing, completion, and search",
  context: `
    This skill helps users manage their tasks.
    
    - Use create_task when users want to add a new task
    - Use list_tasks to show all tasks or filter by status
    - Use complete_task when users finish a task
    - Use search_tasks to find tasks by content
    
    Always confirm task details before creating.
    When listing tasks, organize by priority and due date.
  `,
  tools: [
    new CreateTaskTool(),
    new ListTasksTool(),
    new CompleteTaskTool(),
    new SearchTasksTool()
  ]
});

// Create agent (v3.0.0 pattern)
export const agent = new LuaAgent({
  name: "task-assistant",
  
  persona: `You are a helpful task management assistant.
  
Your role:
- Help users create and organize their tasks
- Keep track of todos and deadlines
- Search for tasks when needed
- Mark tasks as complete

Communication style:
- Friendly and encouraging
- Clear and concise
- Confirm actions before executing
- Provide helpful summaries

Capabilities:
- Create new tasks with title, description, priority, and due date
- List all tasks or filter by status
- Search tasks semantically
- Mark tasks as completed

Always confirm task details with users before creating them.`,

  
  skills: [taskSkill]
});
New in v3.0.0: Use LuaAgent to configure your agent with persona, welcome message, and skills in one place.

Step 5: Test Your Tools

Test Individual Tools

lua test
Select tools and test:
  • create_task: Create a task to buy milk
  • list_tasks: View all pending tasks
  • complete_task: Mark a task as done
  • search_tasks: Find tasks about “meeting”

Test Conversationally

lua chat
Try these in the chat:
  • “Create a task to buy milk”
  • “Show me my pending tasks”
  • “Mark the milk task as done”
  • “Find all tasks about meetings”
Your task management skill is now working!

Step 6: Deploy

When you’re satisfied with your skill:
# Upload to server
lua push

# Deploy to production
lua deploy

Step 7: Test on Real Channels (Optional)

Want to test your agent on WhatsApp, Facebook, Instagram, or other platforms?

Quick Testing Channels

Link your agent to existing Lua channels for instant testing without channel setup
Example for WhatsApp:
https://wa.me/13023778932?text=link-me-to:YOUR_AGENT_ID
Replace YOUR_AGENT_ID with your agent ID from lua.skill.yaml

What You Built

4 Tools

Create, list, complete, and search tasks

Custom Data

Uses Lua’s Data API for storage

Vector Search

Semantic search for finding tasks

Type Safe

Full TypeScript with Zod validation

Next Steps

1

Add More Features

  • Delete tasks
  • Update task details
  • Set reminders
  • Add tags
2

Improve User Experience

  • Better error messages
  • Confirmation prompts
  • Progress indicators

Common Patterns Used

Pattern: Data Storage

await Data.create('collection', data, searchableText);
Creates entries with optional vector search indexing.
await Data.search('collection', query, limit, threshold);
Finds similar items based on meaning, not just exact matches.

Pattern: CRUD Operations

await Data.get('collection', filter);
await Data.getEntry('collection', id);
await Data.update('collection', id, data);
await Data.delete('collection', id);

Pattern: Input Validation

inputSchema = z.object({
  title: z.string(),
  status: z.enum(['pending', 'completed']).optional()
});
Zod schemas provide runtime validation and TypeScript types.

Troubleshooting

Install dependencies:
npm install
Make sure you’re using the correct task ID from the list_tasks response.
  • Lower the score threshold: 0.6 instead of 0.7
  • Check that tasks have searchable text
  • Try broader search terms