Phase 5 / Ep 25: Develop Your First Plugin —— \"Message Counter\"

⏱ Est. reading time: 4 min Updated on 4/13/2026

🎯 Learning Objective: Develop a Plugin from scratch and register it to the Gateway.

1. Goal: Message Counter

Develop a message-counter Plugin to count the number of messages for each user, which can be viewed via the /stats command.

2. Directory Structure

~/.openclaw/plugins/message-counter/
├── manifest.json       # Plugin metadata
├── index.js            # Main entry point
├── data/
│   └── counts.json     # Persistent data
└── README.md

3. manifest.json

{
  "name": "message-counter",
  "version": "1.0.0",
  "description": "Count the number of messages sent by each user",
  "author": "your-name",
  "main": "index.js",
  "hooks": ["onMessage"],
  "commands": ["/stats"]
}

4. Core Logic (index.js)

const fs = require('fs');
const path = require('path');

const DATA_FILE = path.join(__dirname, 'data', 'counts.json');

function loadCounts() {
  if (fs.existsSync(DATA_FILE)) {
    return JSON.parse(fs.readFileSync(DATA_FILE, 'utf8'));
  }
  return {};
}

function saveCounts(counts) {
  fs.writeFileSync(DATA_FILE, JSON.stringify(counts, null, 2));
}

// Hook: Triggered when each message arrives
exports.onMessage = function(message, next) {
  const counts = loadCounts();
  const userId = message.userId;
  counts[userId] = (counts[userId] || 0) + 1;
  saveCounts(counts);
  next(); // Continue passing to the next Plugin
};

// Command: /stats
exports.commands = {
  '/stats': function(message) {
    const counts = loadCounts();
    const total = Object.values(counts).reduce((a, b) => a + b, 0);
    return `📊 Message Statistics\nTotal: ${total} messages\nYour messages: ${counts[message.userId] || 0} messages`;
  }
};

5. Register to Gateway

// openclaw.json
{
  "plugins": {
    "pipeline": ["message-counter"]
  }
}
openclaw gateway restart

6. Testing

# Send a few messages
openclaw chat "Test message 1"
openclaw chat "Test message 2"

# View statistics (via Telegram)
# Send /stats

Coming up next: Ep 26, Plugin in Action — Developing a "Notion Synchronizer" to automatically sync conversation summaries to Notion.