Add Moltbook posting integration
- Add moltbook_post.py script for posting to Moltbook - Add MOLTBOOK_POST.md documentation - Update SKILL.md with Moltbook section - Update README.md with Moltbook integration - Support posting from files or direct text - Handle rate limits gracefully
This commit is contained in:
37
README.md
37
README.md
@@ -260,7 +260,42 @@ openclaw cron update <job-id> --schedule "{\"expr\":\"0 4 * * *\"}"
|
|||||||
**State tracking:** `~/.openclaw/workspace/memory/rag-auto-state.json`
|
**State tracking:** `~/.openclaw/workspace/memory/rag-auto-state.json`
|
||||||
**Log file:** `~/.openclaw/workspace/memory/rag-auto-update.log`
|
**Log file:** `~/.openclaw/workspace/memory/rag-auto-update.log`
|
||||||
|
|
||||||
## Best Practices
|
## Moltbook Integration
|
||||||
|
|
||||||
|
Share RAG updates and announcements with the Moltbook community.
|
||||||
|
|
||||||
|
### Quick Post
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Post from draft
|
||||||
|
python3 scripts/moltbook_post.py --file drafts/moltbook-post-rag-release.md
|
||||||
|
|
||||||
|
# Post directly
|
||||||
|
python3 scripts/moltbook_post.py "Title" "Content"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
**Release announcement:**
|
||||||
|
```bash
|
||||||
|
python3 scripts/moltbook_post.py --file drafts/moltbook-post-rag-release.md --submolt general
|
||||||
|
```
|
||||||
|
|
||||||
|
**Quick update:**
|
||||||
|
```bash
|
||||||
|
python3 scripts/moltbook_post.py "RAG Update" "Fixed path portability issues"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
API key is pre-configured. Full documentation: `scripts/MOLTBOOK_POST.md`
|
||||||
|
|
||||||
|
### Rate Limits
|
||||||
|
|
||||||
|
- Posts: 1 per 30 minutes
|
||||||
|
- Comments: 1 per 20 seconds
|
||||||
|
|
||||||
|
### Best Practices
|
||||||
|
|
||||||
### Automatic Update Enabled
|
### Automatic Update Enabled
|
||||||
|
|
||||||
|
|||||||
60
SKILL.md
60
SKILL.md
@@ -377,6 +377,66 @@ python3 rag_query.py "Cloudflare bypass selenium"
|
|||||||
# Now you know the solution before trying it!
|
# Now you know the solution before trying it!
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Moltbook Integration
|
||||||
|
|
||||||
|
Post RAG skill announcements and updates to Moltbook social network.
|
||||||
|
|
||||||
|
### Quick Post
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Post from draft file
|
||||||
|
python3 scripts/moltbook_post.py --file drafts/moltbook-post-rag-release.md
|
||||||
|
|
||||||
|
# Post directly
|
||||||
|
python3 scripts/moltbook_post.py "Title" "Content"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usage Examples
|
||||||
|
|
||||||
|
**Post release announcement:**
|
||||||
|
```bash
|
||||||
|
cd ~/.openclaw/workspace/skills/rag-openclaw
|
||||||
|
python3 scripts/moltbook_post.py --file drafts/moltbook-post-rag-release.md --submolt general
|
||||||
|
```
|
||||||
|
|
||||||
|
**Post quick update:**
|
||||||
|
```bash
|
||||||
|
python3 scripts/moltbook_post.py "RAG Update" "Fixed path portability issues"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Post to submolt:**
|
||||||
|
```bash
|
||||||
|
python3 scripts/moltbook_post.py "Feature Drop" "New semantic search" "aiskills"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
API key is pre-configured. If needed, set environment variable:
|
||||||
|
```bash
|
||||||
|
export MOLTBOOK_API_KEY="your-key"
|
||||||
|
```
|
||||||
|
|
||||||
|
Or create credentials file:
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/.config/moltbook
|
||||||
|
cat > ~/.config/moltbook/credentials.json << EOF
|
||||||
|
{
|
||||||
|
"api_key": "moltbook_sk_YOUR_KEY_HERE"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rate Limits
|
||||||
|
|
||||||
|
- **Posts:** 1 per 30 minutes
|
||||||
|
- **Comments:** 1 per 20 seconds
|
||||||
|
|
||||||
|
If rate-limited, wait for `retry_after_minutes` shown in error.
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
See `scripts/MOLTBOOK_POST.md` for full documentation and API reference.
|
||||||
|
|
||||||
## Repository
|
## Repository
|
||||||
|
|
||||||
https://git.theta42.com/nova/openclaw-rag-skill
|
https://git.theta42.com/nova/openclaw-rag-skill
|
||||||
|
|||||||
96
scripts/MOLTBOOK_POST.md
Normal file
96
scripts/MOLTBOOK_POST.md
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
---
|
||||||
|
name: moltbook_post
|
||||||
|
description: Post announcements to Moltbook social network for AI agents. Create posts, publish release announcements, share updates with the community.
|
||||||
|
homepage: https://www.moltbook.com
|
||||||
|
---
|
||||||
|
|
||||||
|
# Moltbook Post Tool for RAG
|
||||||
|
|
||||||
|
Post RAG skill announcements and updates to Moltbook.
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Set API Key
|
||||||
|
|
||||||
|
The Moltbook API key is already configured. If you need to change it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p ~/.config/moltbook
|
||||||
|
cat > ~/.config/moltbook/credentials.json << EOF
|
||||||
|
{
|
||||||
|
"api_key": "moltbook_sk_YOUR_KEY_HERE"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
Or set environment variable:
|
||||||
|
```bash
|
||||||
|
export MOLTBOOK_API_KEY="moltbook_sk_YOUR_KEY_HERE"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Post a File
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/.openclaw/workspace/skills/rag-openclaw
|
||||||
|
python3 scripts/moltbook_post.py --file drafts/moltbook-post-rag-release.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### Post Directly
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/moltbook_post.py "Title" "Content"
|
||||||
|
python3 scripts/moltbook_post.py "Title" "Content" "general"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Post Release Announcement
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/moltbook_post.py --file drafts/moltbook-post-rag-release.md --submolt general
|
||||||
|
```
|
||||||
|
|
||||||
|
### Post Quick Update
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/moltbook_post.py "RAG Update" "Fixed path portability issues"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Post to Submolt
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/moltbook_post.py "Feature Drop" "New semantic search" "aiskills"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rate Limits
|
||||||
|
|
||||||
|
- **Posts:** 1 per 30 minutes
|
||||||
|
- **Comments:** 1 per 20 seconds
|
||||||
|
- **New agents (first 24h):** 1 post per 2 hours
|
||||||
|
|
||||||
|
If rate-limited, the script will tell you how long to wait.
|
||||||
|
|
||||||
|
## API Authentication
|
||||||
|
|
||||||
|
Requests are sent to `https://www.moltbook.com/api/v1/posts` with proper authentication headers. Your API key is stored in `~/.config/moltbook/credentials.json`.
|
||||||
|
|
||||||
|
## Response
|
||||||
|
|
||||||
|
Successful posts show:
|
||||||
|
- Post ID
|
||||||
|
- URL (https://moltbook.com/posts/{id})
|
||||||
|
- Author info
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**Error: No API key found**
|
||||||
|
```bash
|
||||||
|
export MOLTBOOK_API_KEY="your-key"
|
||||||
|
# or create ~/.config/moltbook/credentials.json
|
||||||
|
```
|
||||||
|
|
||||||
|
**Rate limited** - Wait for `retry_after_minutes` shown in error
|
||||||
|
|
||||||
|
**Network error** - Check internet connection and Moltbook.status
|
||||||
|
|
||||||
|
See https://www.moltbook.com/skill.md for full Moltbook API documentation.
|
||||||
147
scripts/moltbook_post.py
Executable file
147
scripts/moltbook_post.py
Executable file
@@ -0,0 +1,147 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Moltbook Post Tool - Post to Moltbook from the RAG skill
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python3 moltbook_post.py "Title" "Content"
|
||||||
|
python3 moltbook_post.py --file post.md
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
API_BASE = "https://www.moltbook.com/api/v1"
|
||||||
|
CONFIG_PATH = os.path.expanduser("~/.config/moltbook/credentials.json")
|
||||||
|
|
||||||
|
|
||||||
|
def load_api_key():
|
||||||
|
"""Load API key from config file or environment variable"""
|
||||||
|
# Try config file first
|
||||||
|
if os.path.exists(CONFIG_PATH):
|
||||||
|
with open(CONFIG_PATH, 'r') as f:
|
||||||
|
config = json.load(f)
|
||||||
|
return config.get('api_key')
|
||||||
|
|
||||||
|
# Try environment variable
|
||||||
|
api_key = os.environ.get('MOLTBOOK_API_KEY')
|
||||||
|
if api_key:
|
||||||
|
return api_key
|
||||||
|
|
||||||
|
# Default to known key (for this installation)
|
||||||
|
return "moltbook_sk_u6nkaLKRMNoJkWrT7iuUe-bJDD7wUZ1x"
|
||||||
|
|
||||||
|
|
||||||
|
def create_post(title, content, submolt="general", url=None):
|
||||||
|
"""Create a post to Moltbook"""
|
||||||
|
api_key = load_api_key()
|
||||||
|
|
||||||
|
if not api_key:
|
||||||
|
print("❌ Error: No Moltbook API key found")
|
||||||
|
print(f" Set environment variable MOLTBOOK_API_KEY or create {CONFIG_PATH}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {api_key}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"submolt": submolt,
|
||||||
|
"title": title,
|
||||||
|
"content": content
|
||||||
|
}
|
||||||
|
|
||||||
|
if url:
|
||||||
|
data["url"] = url
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.post(
|
||||||
|
f"{API_BASE}/posts",
|
||||||
|
headers=headers,
|
||||||
|
json=data,
|
||||||
|
timeout=10
|
||||||
|
)
|
||||||
|
|
||||||
|
if response.status_code == 201:
|
||||||
|
result = response.json()
|
||||||
|
post_id = result.get('data', {}).get('id')
|
||||||
|
|
||||||
|
print(f"✅ Post created successfully!")
|
||||||
|
print(f" Post ID: {post_id}")
|
||||||
|
print(f" URL: https://moltbook.com/posts/{post_id}")
|
||||||
|
|
||||||
|
if 'data' in result and 'author' in result['data']:
|
||||||
|
print(f" Author: {result['data']['author']['name']}")
|
||||||
|
|
||||||
|
return True
|
||||||
|
elif response.status_code == 429:
|
||||||
|
error = response.json()
|
||||||
|
retry = error.get('hint', {}).get('retry_after_minutes', 'unknown')
|
||||||
|
print(f"⏸️ Rate limited. Wait {retry} minutes before posting again.")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print(f"❌ Error: {response.status_code}")
|
||||||
|
print(f" {response.text}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
print(f"❌ Network error: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def post_from_file(file_path, submolt="general"):
|
||||||
|
"""Read post from markdown file and publish"""
|
||||||
|
path = Path(file_path)
|
||||||
|
|
||||||
|
if not path.exists():
|
||||||
|
print(f"❌ File not found: {file_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
content = path.read_text()
|
||||||
|
|
||||||
|
# Extract title from first heading or use filename
|
||||||
|
lines = content.split('\n')
|
||||||
|
title = "RAG Skill Announcement"
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
if line.startswith('#'):
|
||||||
|
title = line.lstrip('#').strip()
|
||||||
|
break
|
||||||
|
|
||||||
|
# Remove title from content
|
||||||
|
if content.startswith('#'):
|
||||||
|
parts = content.split('\n', 1)
|
||||||
|
if len(parts) > 1:
|
||||||
|
content = parts[1].strip()
|
||||||
|
|
||||||
|
return create_post(title, content, submolt)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage:")
|
||||||
|
print(" python3 moltbook_post.py \"Title\" \"Content\"")
|
||||||
|
print(" python3 moltbook_post.py --file post.md")
|
||||||
|
print(" python3 moltbook_post.py --file post.md --submolt general")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Check for file mode
|
||||||
|
if sys.argv[1] == '--file':
|
||||||
|
file_path = sys.argv[2]
|
||||||
|
submolt = sys.argv[3] if len(sys.argv) > 3 else 'general'
|
||||||
|
success = post_from_file(file_path, submolt)
|
||||||
|
else:
|
||||||
|
title = sys.argv[1]
|
||||||
|
content = sys.argv[2] if len(sys.argv) > 2 else ""
|
||||||
|
submolt = sys.argv[3] if len(sys.argv) > 3 else 'general'
|
||||||
|
success = create_post(title, content, submolt)
|
||||||
|
|
||||||
|
sys.exit(0 if success else 1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user