chat-logger
Chat Logger stores all incoming and outgoing messages in a SQLite database with timestamps, session identifiers, and optional metadata for later retrieval and analysis. Use this skill when building searchable conversation histories, auditing chat interactions, analyzing communication patterns, debugging dialogue flows, or when users request the ability to track and search past messages.
git clone --depth 1 https://github.com/besoeasy/open-skills /tmp/chat-logger && cp -r /tmp/chat-logger/skills/chat-logger ~/.claude/skills/chat-loggerSKILL.md
# Chat Logger
Log all incoming and outgoing chat messages to a SQLite database for searchable history, analytics, and auditing. Works with any chat system or agent framework.
## When to use
- Building a searchable chat history system
- Auditing and reviewing past conversations
- Creating analytics on chat interactions
- Debugging chat flows and responses
- User asks to track or search conversation history
## Required tools / APIs
- Python standard library (sqlite3, datetime, json)
- Any programming language with SQLite support
No external APIs or services required.
## Database Schema
```sql
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
session_id TEXT,
sender TEXT NOT NULL, -- 'user', 'assistant', or identifier
content TEXT,
metadata TEXT, -- JSON: channel, tools_used, etc.
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_timestamp ON messages(timestamp);
CREATE INDEX idx_session ON messages(session_id);
CREATE INDEX idx_sender ON messages(sender);
-- Automatic purge: delete records older than 1 year
DELETE FROM messages WHERE created_at < datetime('now', '-1 year');
```
**Fields:**
- `id` - Auto-incrementing primary key
- `timestamp` - ISO 8601 timestamp of the message
- `session_id` - Optional session/conversation identifier
- `sender` - Message sender ('user', 'assistant', or custom ID)
- `content` - Message text content
- `metadata` - JSON field for additional data (channel, tools, context)
- `created_at` - Database insertion timestamp
## Basic Implementation
### Python
**Initialize database:**
```python
import sqlite3
from datetime import datetime
from pathlib import Path
import json
# Configure database path
DB_PATH = Path.home() / ".chat_logs" / "messages.db"
def init_db():
"""Initialize database and create tables."""
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
conn = sqlite3.connect(str(DB_PATH))
conn.execute("""
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
session_id TEXT,
sender TEXT NOT NULL,
content TEXT,
metadata TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
""")
conn.execute("CREATE INDEX IF NOT EXISTS idx_timestamp ON messages(timestamp)")
conn.execute("CREATE INDEX IF NOT EXISTS idx_session ON messages(session_id)")
conn.execute("CREATE INDEX IF NOT EXISTS idx_sender ON messages(sender)")
conn.commit()
conn.close()
def purge_old_messages():
"""Delete messages older than 1 year to keep the database size sane."""
conn = sqlite3.connect(str(DB_PATH))
conn.execute("DELETE FROM messages WHERE created_at < datetime('now', '-1 year')")
conn.commit()
conn.close()
# Initialize on import and purge old records
init_db()
purge_old_messages()
```
**Log messages:**
```python
def log_message(sender: str, content: str, session_id: str = None, metadata: dict = None):
"""Log a chat message to the database."""
conn = sqlite3.connect(str(DB_PATH))
try:
conn.execute(
"""INSERT INTO messages (timestamp, session_id, sender, content, metadata)
VALUES (?, ?, ?, ?, ?)""",
(
datetime.utcnow().isoformat(),
session_id,
sender,
content[:10000] if content else None, # Truncate long messages
json.dumps(metadata) if metadata else None
)
)
conn.commit()
finally:
conn.close()
# Usage examples
log_message("user", "Hello, how are you?", session_id="session_123")
log_message("assistant", "I'm doing well, thank you!", session_id="session_123")
log_message("user", "Help me deploy a website", session_id="session_456",
metadata={"channel": "web", "ip": "192.168.1.1"})
```
**Query messages:**
```python
def get_recent_messages(limit: int = 50):
"""Get recent messages."""
conn = sqlite3.connect(str(DB_PATH))
conn.row_factory = sqlite3.Row
cursor = conn.execute(
"SELECT * FROM messages ORDER BY timestamp DESC LIMIT ?",
(limit,)
)
results = cursor.fetchall()
conn.close()
return results
def get_session_history(session_id: str):
"""Get all messages from a specific session."""
conn = sqlite3.connect(str(DB_PATH))
conn.row_factory = sqlite3.Row
cursor = conn.execute(
"SELECT * FROM messages WHERE session_id = ? ORDER BY timestamp ASC",
(session_id,)
)
results = cursor.fetchall()
conn.close()
return results
def search_messages(query: str, limit: int = 20):
"""Search message content."""
conn = sqlite3.connect(str(DB_PATH))
conn.row_factory = sqlite3.Row
cursor = conn.execute(
"SELECT * FROM messages WHERE content LIKE ? ORDER BY timestamp DESC LIMIT ?",
(f"%{query}%", limit)
)
results = cursor.fetchall()
conn.close()
return results
# Usage
messages = get_recent_messages(10)
for msg in messages:
print(f"[{msg['timestamp']}] {msg['sender']}: {msg['content'][:100]}")
# Search
results = search_messages("deploy website")
print(f"Found {len(results)} messages about deploying websites")
```
### Node.js
```javascript
import sqlite3 from "sqlite3";
import { promisify } from "util";
import path from "path";
import os from "os";
const DB_PATH = path.join(os.homedir(), ".chat_logs", "messages.db");
// Initialize database
const db = new sqlite3.Database(DB_PATH);
const run = promisify(db.run.bind(db));
const all = promisify(db.all.bind(db));
await run(`
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
session_id TEXT,
sender TEXT NOT NULL,
content TEXT,
metadata TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
// Log message
async function lEncrypt and decrypt files or streams using age — a simple, modern, and secure encryption tool with small explicit keys, passphrase support, SSH key support, post-quantum hybrid keys, and UNIX-style composability. No config options, no footguns.
Upload and host files anonymously using decentralized storage with Originless and IPFS.
Automate web browsers for AI agents using agent-browser CLI with deterministic element selection.
Star all repositories from a GitHub user automatically. Use when: (1) Supporting open source creators, (2) Bulk discovery of useful projects, or (3) Automating GitHub engagement.
Automatically creates user-facing changelogs from git commits by analyzing commit history, categorizing changes, and transforming technical commits into clear, customer-friendly release notes. Turns hours of manual changelog writing into minutes of automated generation.
Check cryptocurrency wallet balances across multiple blockchains using free public APIs.
Calculate line-of-sight and road distances between two cities using free OpenStreetMap services.
Research and create modern, animated tourism websites for cities with historical facts, places to visit, and colorful designs.