> ## Documentation Index
> Fetch the complete documentation index at: https://docs.heylua.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# User Data Tools Example

> Persistent user storage: state machines, onboarding flows, and preferences

## Overview

**File**: `src/tools/UserDataTool.ts`

Tools demonstrating the User API as a **persistent per-user storage layer** — from simple profile reads to multi-step onboarding state machines.

## Tools Included

### GetUserDataTool

Retrieve current user's information.

```typescript theme={null}
import { LuaTool, User } from 'lua-cli';
import { z } from 'zod';

export class GetUserDataTool implements LuaTool {
  name = "get_user_data";
  description = "Retrieve current user's profile information";
  
  inputSchema = z.object({});

  async execute(input: any) {
    const user = await User.get();
    
    return {
      name: user.name,
      email: user.email,
      id: user.id
    };
  }
}
```

### UpdateUserDataTool

Update user profile information.

```typescript theme={null}
export class UpdateUserDataTool implements LuaTool {
  name = "update_user_data";
  description = "Update user's profile information";
  
  inputSchema = z.object({
    data: z.object({
      name: z.string().optional(),
      phone: z.string().optional(),
      preferences: z.record(z.any()).optional()
    })
  });

  async execute(input: z.infer<typeof this.inputSchema>) {
    const user = await User.get();
    const updated = await user.update(input.data);
    
    return {
      success: true,
      message: "Profile updated successfully",
      user: updated
    };
  }
}
```

## Use Cases

### Onboarding State Machine (Persistent Across Sessions)

The most powerful use of the User API — track multi-step workflows that persist across conversations. If a user leaves mid-onboarding and comes back days later, your agent picks up exactly where they left off.

```typescript theme={null}
export class OnboardingStepTool {
  name = 'onboarding_step';
  description = 'Advance the user through onboarding, resuming where they left off';

  inputSchema = z.object({
    data: z.record(z.any()).optional().describe('Data collected in this step')
  });

  async execute(input: any) {
    const user = await User.get();

    // This persists across conversations — the user can leave and come back
    const step = user.onboardingStep || 'not_started';

    switch (step) {
      case 'not_started':
        user.onboardingStep = 'collecting_info';
        user.onboardingStartedAt = new Date().toISOString();
        user.completedSteps = [];
        await user.save();
        return { nextAction: 'Ask for company name and role' };

      case 'collecting_info':
        // Accumulate data across multiple tool calls
        user.companyName = input.data?.companyName;
        user.role = input.data?.role;
        user.onboardingStep = 'selecting_plan';
        user.completedSteps = [...(user.completedSteps || []), 'info_collected'];
        await user.save();
        return { nextAction: 'Present plan options' };

      case 'selecting_plan':
        user.plan = input.data?.plan;
        user.onboardingStep = 'complete';
        user.onboardingCompletedAt = new Date().toISOString();
        user.completedSteps = [...(user.completedSteps || []), 'plan_selected'];
        await user.save();
        return { message: `Welcome to the ${user.plan} plan, ${user.companyName}!` };

      case 'complete':
        return {
          message: 'Onboarding already complete!',
          completedAt: user.onboardingCompletedAt,
          plan: user.plan
        };
    }
  }
}
```

### Personalized Greeting

```typescript theme={null}
export class GreetUserTool {
  async execute(input: any) {
    const user = await User.get();
    
    const hour = new Date().getHours();
    const greeting = hour < 12 ? 'Good morning'
      : hour < 18 ? 'Good afternoon'
      : 'Good evening';
    
    return {
      message: `${greeting}, ${user.name}! How can I help you today?`
    };
  }
}
```

### User Preferences

```typescript theme={null}
export class SavePreferencesTool {
  async execute(input: { theme: string, language: string }) {
    const user = await User.get();
    
    await user.update({
      preferences: {
        theme: input.theme,
        language: input.language,
        updatedAt: new Date().toISOString()
      }
    });
    
    return { message: "Preferences saved!" };
  }
}
```

### Using save() Method (New!)

```typescript theme={null}
export class UpdateProfileTool {
  async execute(input: { name: string, email: string, phone: string }) {
    const user = await User.get();
    
    // Modify properties directly
    user.name = input.name;
    user.email = input.email;
    user.phone = input.phone;
    
    // Save all changes at once
    await user.save();
    
    return { 
      message: "Profile updated successfully!",
      user: {
        name: user.name,
        email: user.email,
        phone: user.phone
      }
    };
  }
}
```

### Sending Messages to Users (New!)

```typescript theme={null}
export class SendOrderUpdateTool {
  async execute(input: { orderId: string, status: string }) {
    const user = await User.get();
    
    // Send notification to user
    await user.send([
      {
        type: "text",
        text: `Hi ${user.name}! Your order #${input.orderId} is now ${input.status}.`
      },
      {
        type: "text",
        text: "Thank you for your purchase!"
      }
    ]);
    
    return { message: "Notification sent to user" };
  }
}
```

### Sending Images and Files (New!)

```typescript theme={null}
export class SendReceiptTool {
  async execute(input: { orderId: string, receiptData: string, qrCode: string }) {
    const user = await User.get();
    
    // Send receipt with QR code
    await user.send([
      {
        type: "text",
        text: `Receipt for order #${input.orderId}`
      },
      {
        type: "image",
        image: input.qrCode,
        mediaType: "image/png"
      },
      {
        type: "file",
        data: input.receiptData,
        mediaType: "application/pdf"
      }
    ]);
    
    return { message: "Receipt sent to user" };
  }
}
```

## What You'll Learn

<CardGroup cols={2}>
  <Card title="Persistent State" icon="database">
    Store onboarding progress, workflow state, and custom data across sessions
  </Card>

  <Card title="State Machines" icon="arrows-spin">
    Build multi-step flows that resume where the user left off
  </Card>

  <Card title="Platform APIs" icon="server">
    Using Lua's built-in User API
  </Card>

  <Card title="save() Method" icon="floppy-disk">
    Simpler workflow for multiple changes
  </Card>

  <Card title="Messaging Users" icon="message">
    Send proactive notifications
  </Card>

  <Card title="Media Support" icon="image">
    Send images and files to users
  </Card>
</CardGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="User API Reference" icon="book" href="/api/user">
    Complete API documentation
  </Card>

  <Card title="Products Example" icon="box" href="/examples/products">
    See CRUD operations
  </Card>
</CardGroup>
