Skill: vincentqiu/cost-report (version 1.0.2)

--- name: openclaw-cost-tracker description: Track OpenClaw usage costs and provide detailed reports by date and model. Supports daily, weekly, and monthly report formats for Discord and other messaging channels. metadata: { "openclaw": { "emoji": "💰", "os": ["darwin", "linux"], "requires": { "bins": ["jq"] }, "install": [ { "id": "brew", "kind": "brew", "formula": "jq", "bins": ["jq"], "label": "Install jq (JSON parser)", }, ], }, } --- # OpenClaw Cost Tracker ## Overview Precisely track OpenClaw usage costs with detailed reports by date and model type. This skill uses the jq tool to directly parse JSON data from OpenClaw session logs, extracting accurate cost information. Supports multiple report formats: - Daily Reports (today/yesterday costs) - Weekly Reports (current week total/comparison with previous week) - Monthly Reports (current month total/month-over-month growth) ## Quick Start ```bash # Today's cost report bash {baseDir}/scripts/cost_report.sh --today # Yesterday's cost report bash {baseDir}/scripts/cost_report.sh --yesterday # Weekly cost report bash {baseDir}/scripts/cost_report.sh --week # Date range report bash {baseDir}/scripts/cost_report.sh --from 2026-01-01 --to 2026-01-31 ``` ## Cost Calculation Method This script directly extracts cost data from OpenClaw session log files (`~/.openclaw/agents/*/sessions/*.jsonl`): 1. Uses jq to parse JSON data, locating the `message.usage.cost.total` field 2. Calculates totals grouped by date and model 3. Ensures each API call's cost is counted only once ## Discord Output Format ``` 💰 OpenClaw Cost Report (2026-02-04) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Today's Total Cost: $XX.XX (🟢 -XX% vs yesterday) 📊 Model Details: • claude-opus-4-5: $XX.XX (XX%) • gpt-4o: $X.XX (X%) • ... 📈 Weekly Total: $XXX.XX ``` ## Installation Requirements - jq: JSON parsing tool (`brew install jq` or `apt install jq`) - Access to OpenClaw log files

path: README.md
content: # OpenClaw Cost Tracker

Accurately track OpenClaw usage costs with detailed reports by date and model.

## Features

- ✅ Precisely parse API call costs from OpenClaw session logs
- ✅ Group costs by model type
- ✅ Support daily, weekly, and monthly reports
- ✅ Display cost changes (increase/decrease percentage)
- ✅ Compatible with macOS and Linux
- ✅ Beautiful Discord output format
- ✅ Can be set up as automated cron tasks

## Installation

1. Make sure you have the required dependencies:
   ```bash
   # macOS
   brew install jq

   # Ubuntu/Debian
   apt install jq bc
   ```

2. Set script execution permissions:
   ```bash
   chmod +x scripts/cost_report.sh
   ```

## Usage

```bash
# Today's cost report
npm start

# Or run the script directly
./scripts/cost_report.sh --today

# Yesterday's cost report
./scripts/cost_report.sh --yesterday

# Weekly cost report
./scripts/cost_report.sh --week

# Date range report
./scripts/cost_report.sh --from 2026-01-01 --to 2026-01-31

# Generate Discord format report
./scripts/cost_report.sh --today --format discord

# Generate JSON format report
./scripts/cost_report.sh --today --format json
```

## Automated Reports (Cron)

See the `config/cron-examples.json` file to learn how to set up automated report tasks. Use OpenClaw's cron functionality to easily set up daily/weekly cost reports.

## Calculation Method

This tool extracts accurate API call cost data directly from OpenClaw session log files, ensuring precise and reliable report results:

1. Scan all session JSONL files for records on the target date
2. Use jq to parse the `message.usage.cost.total` field in each record
3. Group by model and calculate totals
4. Avoid data duplication or loss issues caused by session compaction

## Notes

- Ensure you have read permissions for the OpenClaw sessions directory
- Processing large session files may take longer
- If costs are 0, it may be because the API provider did not provide cost data

## Technical Details

- Uses jq to parse JSON data
- Compatible with macOS and Linux date handling
- Supports cost calculations grouped by model
- Chinese-style color indicators for changes (🔴up / 🟢down)

path: package.json
content: {
  "name": "openclaw-cost-tracker",
  "version": "1.0.0",
  "description": "Track OpenClaw usage costs with detailed reports by date and model",
  "main": "cli.js",
  "bin": {
    "openclaw-cost": "./cli.js"
  },
  "scripts": {
    "start": "node cli.js --today",
    "test": "node cli.js --today --format text"
  },
  "keywords": [
    "openclaw",
    "cost",
    "usage",
    "tracking",
    "report",
    "llm"
  ],
  "author": "OpenClaw Team",
  "license": "MIT",
  "dependencies": {},
  "engines": {
    "node": ">=12.0.0"
  },
  "openclaw": {
    "emoji": "💰",
    "description": "Track OpenClaw usage costs with detailed reports by date and model",
    "requires": {
      "bins": ["jq", "bash"]
    }
  }
}

path: cli.js
content: #!/usr/bin/env node

/**
 * OpenClaw Cost Tracker CLI
 * 
 * Provides a command line interface for calling the cost_report.sh script
 */

const { execSync } = require('child_process');
const { resolve, join } = require('path');
const { existsSync } = require('fs');

// Get script directory
const baseDir = __dirname;
const scriptPath = join(baseDir, 'scripts', 'cost_report.sh');

// Ensure script exists and is executable
if (!existsSync(scriptPath)) {
  console.error(`Error: Script not found at ${scriptPath}`);
  process.exit(1);
}

// Set script executable permissions
try {
  execSync(`chmod +x "${scriptPath}"`);
} catch (error) {
  console.warn(`Warning: Unable to set script execution permissions: ${error.message}`);
}

// Pass command line arguments to the script
const args = process.argv.slice(2);

try {
  // Set environment variables for the script
  const env = {
    ...process.env,
    LC_ALL: 'en_US.UTF-8', // Ensure English locale for number formatting
  };
  
  // Run script and capture output
  const output = execSync(`"${scriptPath}" ${args.map(arg => `"${arg}"`).join(' ')}`, {
    env,
    stdio: 'pipe',
    encoding: 'utf-8'
  });
  
  // Output the result
  console.log(output.toString());
} catch (error) {
  // Handle script execution errors
  if (error.stdout) {
    console.log(error.stdout.toString());
  }
  if (error.stderr) {
    console.error(error.stderr.toString());
  }
  process.exit(error.status || 1);
}

path: scripts/cost_report.sh
content: #!/bin/bash
#
# OpenClaw Cost Tracker
# Track and report OpenClaw usage costs
#

# Constants
OPENCLAW_SESSIONS_DIR=~/.openclaw/agents
SYMLINK_SESSIONS_DIR=~/.clawdbot/agents
OUTPUT_FORMAT="text" # text, json, discord
REPORT_TYPE="daily" # daily, weekly, monthly, custom
START_DATE=""
END_DATE=""
DECIMAL_PLACES=2
CURRENCY_SYMBOL="$"
HIDE_ZERO_COST=true  # Hide zero-cost models
SHOW_ERRORS=false    # Show error status model calls

# Help information
show_help() {
    echo "OpenClaw Cost Tracker - Usage Cost Reporting Tool"
    echo
    echo "Usage: $(basename "$0") [options]"
    echo
    echo "Options:"
    echo "  --today                 Display today's cost report"
    echo "  --yesterday             Display yesterday's cost report"
    echo "  --format FORMAT         Output format (text, json, discord)"
    echo "  --show-all              Show all models (including zero-cost models)"
    echo "  --show-errors           Show error status call information"
    echo "  --help                  Display this help information"
    echo
    echo "Examples:"
    echo "  $(basename "$0") --today"
    echo "  $(basename "$0") --yesterday --format discord"
    echo "  $(basename "$0") --yesterday --show-all --show-errors"
    echo
}

# Parameter parsing
while [[ $# -gt 0 ]]; do
    case "$1" in
        --today)
            REPORT_TYPE="daily"
            TODAY=$(date +%Y-%m-%d)
            START_DATE="$TODAY"
            END_DATE="$TODAY"
            shift
            ;;
        --yesterday)
            REPORT_TYPE="daily"
            YESTERDAY=$(date -v-1d +%Y-%m-%d 2>/dev/null || date -d "yesterday" +%Y-%m-%d)
            START_DATE="$YESTERDAY"
            END_DATE="$YESTERDAY"
            shift
            ;;
        --format)
            shift
            OUTPUT_FORMAT="$1"
            shift
            ;;
        --show-all)
            HIDE_ZERO_COST=false
            shift
            ;;
        --show-errors)
            SHOW_ERRORS=true
            shift
            ;;
        --help)
            show_help
            exit 0
            ;;
        *)
            echo "Error: Unknown option $1"
            show_help
            exit 1
            ;;
    esac
done

# Check if jq is installed
if ! command -v jq &> /dev/null; then
    echo "Error: jq command not found. Please install jq: brew install jq (macOS) or apt install jq (Linux)"
    exit 1
fi

# Validate parameters
if [ -z "$START_DATE" ]; then
    echo "Error: No date specified. Use --today or --yesterday"
    show_help
    exit 1
fi

# Determine which sessions directory to use
if [ -d "$OPENCLAW_SESSIONS_DIR" ]; then
    SESSIONS_DIR="$OPENCLAW_SESSIONS_DIR"
elif [ -d "$SYMLINK_SESSIONS_DIR" ]; then
    SESSIONS_DIR="$SYMLINK_SESSIONS_DIR"
else
    echo "Error: OpenClaw sessions directory not found"
    exit 1
fi

# Get yesterday's date
get_yesterday() {
    if [[ "$(uname)" == "Darwin" ]]; then
        # macOS
        date -v-1d +%Y-%m-%d
    else
        # Linux
        date -d "yesterday" +%Y-%m-%d
    fi
}

# Calculate costs for given date
get_cost_for_date() {
    local target_date="$1"
    local total=0
    local temp_file=$(mktemp)
    local error_file=$(mktemp)
    
    # Collect sessions from all agents
    for agent_dir in "$SESSIONS_DIR"/*; do
        if [ -d "$agent_dir/sessions" ]; then
            for session_file in "$agent_dir/sessions"/*.jsonl; do
                if [ -f "$session_file" ]; then
                    # Extract cost records for specific date and save to temp file
                    grep -a "\"timestamp\":\"$target_date" "$session_file" 2>/dev/null | \
                    grep -a "cost\|totalTokens" | \
                    jq -c 'select(.message.usage != null) | {
                        model: .message.model,
                        timestamp: .timestamp,
                        cost: .message.usage.cost.total,
                        totalTokens: .message.usage.totalTokens,
                        inputTokens: .message.usage.input,
                        outputTokens: .message.usage.output,
                        errorMessage: .message.errorMessage
                    }' 2>/dev/null >> "$temp_file" || true
                    
                    # If showing errors, extract error information
                    if [ "$SHOW_ERRORS" = true ]; then
                        grep -a "\"timestamp\":\"$target_date" "$session_file" 2>/dev/null | \
                        grep -a "errorMessage" | \
                        jq -c 'select(.message.errorMessage != null) | {
                            model: .message.model,
                            timestamp: .timestamp,
                            errorMessage: .message.errorMessage,
                            stopReason: .message.stopReason
                        }' 2>/dev/null >> "$error_file" || true
                    fi
                fi
            done
        fi
    done
    
    # If temp file is empty, return empty JSON
    if [ ! -s "$temp_file" ]; then
        rm "$temp_file" "$error_file"
        echo "{\"total\":0,\"models\":[],\"errors\":[]}"
        return
    fi
    
    # Analyze results and group by model
    local filter_expr=''
    if [ "$HIDE_ZERO_COST" = true ]; then
        filter_expr='| map(select(.cost > 0.001))'
    fi
    
    # Read error file
    local errors_json="[]"
    if [ "$SHOW_ERRORS" = true ] && [ -s "$error_file" ]; then
        errors_json=$(cat "$error_file" | jq -s '
        group_by(.model) | map({
            model: .[0].model,
            count: length,
            errors: map(.errorMessage) | unique
        })' 2>/dev/null || echo "[]")
    fi
    
    # Process cost and token data
    cat "$temp_file" | jq -s "
    {
        total: map(.cost) | add,
        totalTokens: map(.totalTokens) | add,
        models: group_by(.model) | map({
            model: .[0].model,
            cost: map(.cost) | add,
            totalTokens: map(.totalTokens) | add,
            inputTokens: map(.inputTokens) | add,
            outputTokens: map(.outputTokens) | add,
            calls: length
        }) | sort_by(-.cost) $filter_expr,
        errors: $errors_json
    }" 2>/dev/null || echo "{\"total\":0,\"totalTokens\":0,\"models\":[],\"errors\":[]}"
    
    rm "$temp_file" "$error_file"
}

# Generate report
generate_report() {
    # Get current date data
    local current_data=$(get_cost_for_date "$START_DATE")
    local total=$(echo "$current_data" | jq -r '.total')
    local totalTokens=$(echo "$current_data" | jq -r '.totalTokens')
    local models=$(echo "$current_data" | jq -r '.models')
    local errors=$(echo "$current_data" | jq -r '.errors')
    
    # If today's report, get yesterday's data for comparison
    local comparison_data=""
    local comparison_total=0
    local percentage_change=0
    local change_indicator=""
    
    if [ "$START_DATE" = "$(date +%Y-%m-%d)" ]; then
        local yesterday=$(get_yesterday)
        comparison_data=$(get_cost_for_date "$yesterday")
        comparison_total=$(echo "$comparison_data" | jq -r '.total')
        
        # Calculate percentage change
        if (( $(echo "$comparison_total > 0" | bc -l 2>/dev/null || echo 0) )); then
            percentage_change=$(echo "scale=1; ($total - $comparison_total) / $comparison_total * 100" | bc -l 2>/dev/null || echo 0)
            
            # Determine increase/decrease indicator
            if (( $(echo "$percentage_change > 0" | bc -l 2>/dev/null || echo 0) )); then
                if [ "$OUTPUT_FORMAT" = "discord" ]; then
                    change_indicator="🔴" # Increase (Chinese style: red=up)
                else
                    change_indicator="▲"
                fi
            elif (( $(echo "$percentage_change < 0" | bc -l 2>/dev/null || echo 0) )); then
                if [ "$OUTPUT_FORMAT" = "discord" ]; then
                    change_indicator="🟢" # Decrease (Chinese style: green=down)
                else
                    change_indicator="▼"
                fi
            else
                if [ "$OUTPUT_FORMAT" = "discord" ]; then
                    change_indicator="⚪" # No change
                else
                    change_indicator="○"
                fi
            fi
        fi
    fi
    
    # Generate report based on output format
    if [ "$OUTPUT_FORMAT" = "json" ]; then
        # JSON output
        echo "{
            \"total\": $total,
            \"totalTokens\": $totalTokens,
            \"models\": $models,
            \"errors\": $errors,
            \"comparisonTotal\": $comparison_total,
            \"percentageChange\": $percentage_change,
            \"date\": \"$START_DATE\"
        }"
    elif [ "$OUTPUT_FORMAT" = "discord" ]; then
        # Discord format output
        local report_title=""
        
        if [ "$START_DATE" = "$(date +%Y-%m-%d)" ]; then
            report_title="💰 OpenClaw Today's Cost Report"
        elif [ "$START_DATE" = "$(get_yesterday)" ]; then
            report_title="💰 OpenClaw Yesterday's Cost Report"
        else
            report_title="💰 OpenClaw Cost Report"
        fi
        
        echo "$report_title ($START_DATE)"
        echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
        
        # Format total cost
        local formatted_total=$(printf "$CURRENCY_SYMBOL%.${DECIMAL_PLACES}f" "$total")
        
        if [ -n "$comparison_data" ] && [ "$comparison_total" != "0" ]; then
            echo "Total Cost: $formatted_total ($change_indicator ${percentage_change}% vs yesterday) | Total Tokens: $(printf "%'d" $totalTokens)"
        else
            echo "Total Cost: $formatted_total | Total Tokens: $(printf "%'d" $totalTokens)"
        fi
        
        # Model details
        echo -e "\n📊 Model Details:"
        
        # Calculate model count
        local model_count=$(echo "$models" | jq -r '. | length')
        
        if [ "$model_count" -eq 0 ]; then
            echo "• No cost data available"
        else
            echo "$models" | jq -c '.[]' | while read -r model_data; do
                local model_name=$(echo "$model_data" | jq -r '.model')
                local model_cost=$(echo "$model_data" | jq -r '.cost')
                local model_tokens=$(echo "$model_data" | jq -r '.totalTokens')
                local input_tokens=$(echo "$model_data" | jq -r '.inputTokens')
                local output_tokens=$(echo "$model_data" | jq -r '.outputTokens')
                local calls=$(echo "$model_data" | jq -r '.calls')
                
                local formatted_cost=$(printf "$CURRENCY_SYMBOL%.${DECIMAL_PLACES}f" "$model_cost")
                local percentage=0
                
                if (( $(echo "$total > 0" | bc -l 2>/dev/null || echo 0) )); then
                    percentage=$(echo "scale=1; ($model_cost / $total) * 100" | bc -l 2>/dev/null || echo 0)
                fi
                
                echo "• $model_name: $formatted_cost (${percentage}%) | Tokens: $(printf "%'d" $model_tokens) [in:$(printf "%'d" $input_tokens)/out:$(printf "%'d" $output_tokens)] | Calls: $calls"
            done
        fi
        
        # Show error information
        if [ "$SHOW_ERRORS" = true ]; then
            local error_count=$(echo "$errors" | jq -r '. | length')
            
            if [ "$error_count" -gt 0 ]; then
                echo -e "\n⚠️ Model Errors:"
                echo "$errors" | jq -c '.[]' | while read -r error_data; do
                    local model_name=$(echo "$error_data" | jq -r '.model')
                    local count=$(echo "$error_data" | jq -r '.count')
                    local error_msgs=$(echo "$error_data" | jq -r '.errors | join(", ")')
                    
                    echo "• $model_name: $count errors - $error_msgs"
                done
            fi
        fi
    else
        # Default text output
        local report_title=""
        
        if [ "$START_DATE" = "$(date +%Y-%m-%d)" ]; then
            report_title="OpenClaw Today's Cost Report"
        elif [ "$START_DATE" = "$(get_yesterday)" ]; then
            report_title="OpenClaw Yesterday's Cost Report"
        else
            report_title="OpenClaw Cost Report"
        fi
        
        echo "$report_title ($START_DATE)"
        echo "-------------------------------"
        
        # Format total cost
        local formatted_total=$(printf "$CURRENCY_SYMBOL%.${DECIMAL_PLACES}f" "$total")
        
        if [ -n "$comparison_data" ] && [ "$comparison_total" != "0" ]; then
            echo "Total Cost: $formatted_total ($change_indicator ${percentage_change}% vs yesterday)"
            echo "Total Tokens: $(printf "%'d" $totalTokens)"
        else
            echo "Total Cost: $formatted_total"
            echo "Total Tokens: $(printf "%'d" $totalTokens)"
        fi
        
        # Model details
        echo -e "\nModel Details:"
        
        # Calculate model count
        local model_count=$(echo "$models" | jq -r '. | length')
        
        if [ "$model_count" -eq 0 ]; then
            echo "  No cost data available"
        else
            echo "$models" | jq -c '.[]' | while read -r model_data; do
                local model_name=$(echo "$model_data" | jq -r '.model')
                local model_cost=$(echo "$model_data" | jq -r '.cost')
                local model_tokens=$(echo "$model_data" | jq -r '.totalTokens')
                local input_tokens=$(echo "$model_data" | jq -r '.inputTokens')
                local output_tokens=$(echo "$model_data" | jq -r '.outputTokens')
                local calls=$(echo "$model_data" | jq -r '.calls')
                
                local formatted_cost=$(printf "$CURRENCY_SYMBOL%.${DECIMAL_PLACES}f" "$model_cost")
                local percentage=0
                
                if (( $(echo "$total > 0" | bc -l 2>/dev/null || echo 0) )); then
                    percentage=$(echo "scale=1; ($model_cost / $total) * 100" | bc -l 2>/dev/null || echo 0)
                fi
                
                echo "  $model_name:"
                echo "    Cost: $formatted_cost (${percentage}%)"
                echo "    Tokens: $(printf "%'d" $model_tokens) [input:$(printf "%'d" $input_tokens)/output:$(printf "%'d" $output_tokens)]"
                echo "    Calls: $calls"
            done
        fi
        
        # Show error information
        if [ "$SHOW_ERRORS" = true ]; then
            local error_count=$(echo "$errors" | jq -r '. | length')
            
            if [ "$error_count" -gt 0 ]; then
                echo -e "\nModel Errors:"
                echo "$errors" | jq -c '.[]' | while read -r error_data; do
                    local model_name=$(echo "$error_data" | jq -r '.model')
                    local count=$(echo "$error_data" | jq -r '.count')
                    local error_msgs=$(echo "$error_data" | jq -r '.errors | join(", ")')
                    
                    echo "  $model_name: $count errors"
                    echo "    Error messages: $error_msgs"
                done
            fi
        fi
    fi
}

# Main function
main() {
    # Generate report
    generate_report
}

main

path: scripts/report_discord.sh
content: #!/bin/bash
#
# OpenClaw Cost Tracker - Discord 报告版本
# 简化版，仅用于 Discord 报告
#

cd "$(dirname "$0")"

# 判断是昨日还是今日报告
if [ "$1" = "yesterday" ]; then
  ./cost_report.sh --yesterday --format discord --show-errors 
else
  ./cost_report.sh --today --format discord --show-errors 
fi

# 额外显示 Kimi 模型错误信息
if [ "$1" = "yesterday" ]; then
  YESTERDAY=$(date -v-1d +%Y-%m-%d 2>/dev/null || date -d "yesterday" +%Y-%m-%d)
  DATE=$YESTERDAY
else
  DATE=$(date +%Y-%m-%d)
fi

echo -e "\n📌 Kimi 模型错误详情:"
cd ~/.openclaw/agents/main/sessions && 
for f in *.jsonl; do
  grep -a "\"timestamp\":\"$DATE" "$f" 2>/dev/null | 
  grep -a "\"model\":\"kimi" | 
  grep -a "errorMessage" | 
  head -3 |
  jq -c '.message.model + ": " + .message.errorMessage' | 
  sed 's/"//g'
done

path: references/JSONL_FORMAT.md
content: # OpenClaw JSONL 日志格式

本文档描述了 OpenClaw 会话日志文件的格式，特别是与费用计算相关的字段。

## 日志文件位置

OpenClaw 将会话日志存储在以下位置：

```
~/.openclaw/agents/{agent_id}/sessions/{session_id}.jsonl
```

在某些系统上，可能会通过符号链接指向：

```
~/.clawdbot/agents/{agent_id}/sessions/{session_id}.jsonl
```

## 文件格式

每个日志文件是 JSONL 格式（每行一个 JSON 对象）。每行记录一条消息、工具调用或系统事件。

## 费用相关字段

关键字段路径：

```
message.usage.cost.total       # 总费用
message.usage.cost.input       # 输入成本
message.usage.cost.output      # 输出成本
message.usage.cost.cacheRead   # 缓存读取成本
message.usage.cost.cacheWrite  # 缓存写入成本
```

## 示例记录

以下是一个包含费用信息的记录示例：

```json
{
  "type": "message",
  "id": "a08ab7f3",
  "parentId": "a60970bd",
  "timestamp": "2026-02-04T15:34:59.833Z",
  "message": {
    "role": "assistant",
    "content": [
      {"type": "text", "text": "我需要获取OpenClaw的使用费用数据。让我来为您查询当天的使用费用预估。"},
      {"type": "toolCall", "id": "toolu_01PUpUMycdh9bNYUcxG4wUS2", "name": "session_status", "arguments": {}}
    ],
    "api": "anthropic-messages",
    "provider": "anthropic",
    "model": "claude-3-7-sonnet-latest",
    "usage": {
      "input": 3,
      "output": 71,
      "cacheRead": 17138,
      "cacheWrite": 326,
      "totalTokens": 17538,
      "cost": {
        "input": 0.000009,
        "output": 0.001065,
        "cacheRead": 0.0051414,
        "cacheWrite": 0.0012225,
        "total": 0.007437899999999999
      }
    },
    "stopReason": "toolUse",
    "timestamp": 1770219296684
  }
}
```

## 特殊情况

1. **未包含费用数据**：某些记录可能不包含费用信息，如空消息、错误响应或免费模型。

2. **零成本模型**：某些模型（如本地模型）可能报告零成本。

3. **缓存机制**：OpenClaw 使用缓存机制减少重复 API 调用，缓存读写也有相应成本。

4. **错误响应**：API 调用失败的记录可能有 `errorMessage` 字段，但没有完整的 `usage` 或 `cost` 信息。

## 注意事项

- 避免通过 `totalTokens` 字段计算成本，因为不同的模型有不同的价格。
- 使用 jq 等工具解析 JSON 比使用文本正则表达式更可靠。
- 时区问题：`timestamp` 字段采用 ISO 格式，包含 UTC 时间，需要根据本地时区调整。

path: config/cron-examples.json
content: {
  "jobs": [
    {
      "name": "daily-cost-report",
      "description": "每日发送 OpenClaw 费用报告到 Discord",
      "schedule": {
        "kind": "cron",
        "expr": "20 8 * * *",
        "tz": "Asia/Shanghai"
      },
      "sessionTarget": "isolated",
      "payload": {
        "kind": "agentTurn",
        "message": "生成今日 OpenClaw 费用报告并发送到 #dailyreport 频道。使用 openclaw-cost-tracker 技能，显示昨日费用和本周累计。",
        "model": "openai/gpt-4o-mini",
        "timeoutSeconds": 120,
        "deliver": true,
        "channel": "discord",
        "to": "dailyreport"
      },
      "enabled": true
    },
    {
      "name": "weekly-cost-report",
      "description": "每周一发送 OpenClaw 周费用报告到 Discord",
      "schedule": {
        "kind": "cron",
        "expr": "30 9 * * 1",
        "tz": "Asia/Shanghai"
      },
      "sessionTarget": "isolated",
      "payload": {
        "kind": "agentTurn",
        "message": "生成 OpenClaw 上周费用报告并发送到 #dailyreport 频道。使用 openclaw-cost-tracker 技能，--week 参数显示详细模型使用情况。",
        "model": "openai/gpt-4o-mini",
        "timeoutSeconds": 120,
        "deliver": true,
        "channel": "discord", 
        "to": "dailyreport"
      },
      "enabled": true
    }
  ]
}

Security scan verdicts — ClawScan: suspicious | static analysis: suspicious | VirusTotal: clean | SkillSpector: suspicious (HIGH)