> ## 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.

# Debugging Skills

> How to inspect tool return values and debug skill behavior at runtime

## The Core Problem

A common debugging mistake is deploying five times to fix the same bug, when a single log line plus one deployment would have shown you the root cause immediately.

If you're patching against test failures rather than the actual return shape, stop and add a `console.log` first — then deploy once.

## The 5-Step Debug Loop

<Steps>
  <Step title="Add a console.log to the suspicious spot">
    Log the actual value — not a guess, the real thing:

    ```typescript theme={null}
    async execute(input: any) {
      const results = await Data.search('articles', input.query, 5, 0.7);
      
      // ✅ Log the raw return value FIRST
      console.log('Data.search result:', JSON.stringify(results, null, 2));
      
      // Don't touch the rest of the code yet
      return results.map(entry => ({ id: entry.id, title: entry.title }));
    }
    ```

    Log the entire object so you see the actual shape, not what you assumed it would be.
  </Step>

  <Step title="Push to sandbox (not production)">
    ```bash theme={null}
    lua push
    ```

    Or use sandbox mode for even faster iteration — no push needed:

    ```bash theme={null}
    lua chat
    # Select "Sandbox" when prompted
    ```

    In sandbox mode, `lua chat` compiles and uses your local code directly. Use this for rapid iteration before committing to a push.
  </Step>

  <Step title="Send ONE test message">
    ```bash theme={null}
    # Non-interactive: send a single message and exit
    lua chat -m "search for thriller movies"
    ```

    Or in interactive mode:

    ```bash theme={null}
    lua chat
    # Type your test message, then Ctrl+C
    ```

    Send the **minimum message needed to trigger the tool**. Don't run a full conversation — you need one clean execution to inspect.
  </Step>

  <Step title="Check logs immediately">
    ```bash theme={null}
    # See the most recent 10 skill executions
    lua logs --type skill --limit 10

    # Filter to a specific skill by name
    lua logs --type skill --name my-skill --limit 5

    # JSON output for piping/scripting
    lua logs --type skill --json | head -100
    ```

    Your `console.log` output appears in the log message body. Look for the `🔍 DEBUG` or `ℹ️ INFO` entries — they contain your logged values.

    **Example output:**

    ```
    🔍 [4/28/2026, 11:45:30 AM] DEBUG
       Skill Name: search-skill
       Skill ID:   skill_abc123
       Tool Name:  search_articles
       Data.search result: [
         {
           "id": "entry_xyz",
           "title": "Inception",
           "score": 0.92
         }
       ]
    ```

    Now you can see the exact shape of what was returned and fix accordingly.
  </Step>

  <Step title="Fix once, not five times">
    You now know:

    * **Exact shape** of the return value
    * **Which fields exist** (and which don't)
    * **What the actual values** look like

    Fix the code, push once, verify with `lua logs`. Repeat until correct.
  </Step>
</Steps>

## Suppressing CLI hints

All post-action hints can be silenced with:

```bash theme={null}
LUA_NO_HINTS=1 lua push all --force --auto-deploy
```

Set `LUA_NO_HINTS=true` (or `yes`) in your shell profile or CI environment to disable hints globally. This is useful in CI/CD pipelines that capture only command output.

## Reading lua logs Output

```bash theme={null}
lua logs --type skill --limit 20
```

### Log entry anatomy

```
✅ [4/28/2026, 11:45:30 AM] COMPLETE
   Skill Name: my-search-skill
   Skill ID:   skill_abc123
   Tool Name:  search_articles
   Duration:   234ms
   Execute function completed
```

| Field            | Meaning                                            |
| ---------------- | -------------------------------------------------- |
| Icon + timestamp | When the log was created                           |
| Log type         | ERROR, WARN, DEBUG, INFO, START, COMPLETE          |
| Skill/Tool Name  | Which component ran                                |
| Duration         | Execution time in ms                               |
| Message          | The actual log content (your `console.log` output) |

### Log types

| Type       | Color  | Means                                           |
| ---------- | ------ | ----------------------------------------------- |
| ❌ ERROR    | Red    | Tool threw an exception — check the stack trace |
| ⚠️ WARN    | Yellow | Non-fatal issue, tool continued                 |
| 🔍 DEBUG   | Blue   | `console.log` output from your tool code        |
| ℹ️ INFO    | Cyan   | Operational status messages                     |
| ▶️ START   | Green  | Tool execution began                            |
| ✅ COMPLETE | Green  | Tool execution finished successfully            |

### Filter by component type

```bash theme={null}
# Skill tool execution
lua logs --type skill --limit 20

# Webhook execution
lua logs --type webhook --name stripe-webhook --limit 10

# Scheduled job execution
lua logs --type job --name daily-report --limit 5

# Preprocessor/Postprocessor
lua logs --type preprocessor --limit 10
lua logs --type postprocessor --limit 10

# User messages and agent responses
lua logs --type user_message --limit 20
lua logs --type agent_response --limit 20

# All logs
lua logs --type all --limit 50
```

## When to Use lua test vs lua chat vs lua logs

| Goal                                                            | Use                                 |
| --------------------------------------------------------------- | ----------------------------------- |
| Test a tool with exact input before touching the server         | `lua test`                          |
| Test a conversational flow, verify the AI calls the right tools | `lua chat` (sandbox)                |
| See what actually ran in production                             | `lua logs --type skill`             |
| Debug why an API call returned unexpected data                  | `console.log` + push + `lua logs`   |
| Check if a job actually ran and what it returned                | `lua logs --type job --name my-job` |
| Verify a webhook received and processed correctly               | `lua logs --type webhook`           |

## console.log Debugging Patterns

### Log a full API return value

```typescript theme={null}
const results = await Data.search('articles', input.query, 5, 0.7);
console.log('[DEBUG] Data.search result type:', typeof results, Array.isArray(results) ? `array[${results.length}]` : 'not array');
console.log('[DEBUG] Data.search result:', JSON.stringify(results, null, 2));
```

### Log individual entries

```typescript theme={null}
const results = await Data.search('articles', input.query, 5);
results.forEach((entry, i) => {
  console.log(`[DEBUG] entry[${i}]:`, JSON.stringify({
    id: entry.id,
    score: entry.score,
    keys: Object.keys(entry.data || {}),
    sample: entry.title || entry.data?.title || '(no title field)'
  }));
});
```

### Log before and after transformation

```typescript theme={null}
const raw = await Data.get('orders', { status: 'pending' });
console.log('[DEBUG] Data.get result — pagination:', JSON.stringify(raw.pagination));
console.log('[DEBUG] Data.get result — entry count:', raw.data.length);
if (raw.data.length > 0) {
  console.log('[DEBUG] First entry sample:', JSON.stringify(raw.data[0]));
}

const mapped = raw.data.map(entry => ({
  id: entry.id,
  orderId: entry.data.orderId,
  total: entry.data.total
}));
console.log('[DEBUG] After mapping:', JSON.stringify(mapped.slice(0, 2)));
```

## Common Bugs and How to Spot Them

### Bug: results.data is undefined (Data.search)

```
[DEBUG] Data.search result type: object array[3]
[DEBUG] Data.search result: [{"id":"entry_abc","data":{"title":"Inception"},"score":0.92}]
```

`results.data` would be `undefined` — there is no `.data` wrapper on the array. Use `results[0].data.title` for the entry payload, or `results[0].title` via the Proxy shortcut.

### Bug: entry.title is undefined (Data.get)

```
[DEBUG] First entry sample: {"id":"entry_xyz","data":{"title":"The Matrix"}}
```

`entry.title` would be `undefined` — `Data.get` entries are raw, not proxied. Use `entry.data.title`.

### Bug: products.data is undefined (Products.search)

```
[DEBUG] Products.search result type: object
[DEBUG] Products.search result: {"products":[{"id":"prod_1","name":"Laptop"}]}
```

`results.data` doesn't exist on `ProductSearchInstance`. Use `results.products` or `results.map(p => p.name)`.

## Removing Debug Logs Before Production

Once the bug is fixed, clean up your logs. Production logs are visible to your whole team and consume log storage.

```typescript theme={null}
// ❌ Don't leave these in production code
console.log('[DEBUG] raw result:', JSON.stringify(results));

// ✅ Leave meaningful operational logs
console.log(`Processed ${results.length} search results for query: "${input.query}"`);
```

## Related

<CardGroup cols={2}>
  <Card title="lua logs Command" icon="terminal" href="/cli/logs-command">
    Full reference for the logs command and all filter options
  </Card>

  <Card title="lua test Command" icon="flask" href="/cli/overview">
    Test tools locally before pushing
  </Card>

  <Card title="Data API" icon="database" href="/api/data">
    Data API return shapes reference
  </Card>

  <Card title="Troubleshooting" icon="circle-question" href="/cli/troubleshooting">
    Common errors and solutions
  </Card>
</CardGroup>
