chat-logger
Log all chat messages to a SQLite database for searchable history and audit. Use when: (1) Building chat history, (2) Auditing conversations, (3) Searching past messages, or (4) User asks to log chats.
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.