@clawhub-mmyg11-a561e26893
End-to-end AI video generation - create videos from text prompts using image generation, video synthesis, voice-over, and editing. Supports OpenAI DALL-E, Re...
---
name: ai-video-gen-local
description: End-to-end AI video generation - create videos from text prompts using image generation, video synthesis, voice-over, and editing. Supports OpenAI DALL-E, Replicate models, LumaAI, Runway, and FFmpeg editing.
---
# AI Video Generation Skill
Generate complete videos from text descriptions using AI.
## Capabilities
1. **Image Generation** - DALL-E 3, Stable Diffusion, Flux
2. **Video Generation** - LumaAI, Runway, Replicate models
3. **Voice-over** - OpenAI TTS, ElevenLabs
4. **Video Editing** - FFmpeg assembly, transitions, overlays
## Quick Start
```bash
# Generate a complete video
python skills/ai-video-gen/generate_video.py --prompt "A sunset over mountains" --output sunset.mp4
# Just images to video
python skills/ai-video-gen/images_to_video.py --images img1.png img2.png --output result.mp4
# Add voiceover
python skills/ai-video-gen/add_voiceover.py --video input.mp4 --text "Your narration" --output final.mp4
```
## Setup
### Required API Keys
Add to your environment or `.env` file:
```bash
# Image Generation (pick one)
OPENAI_API_KEY=sk-... # DALL-E 3
REPLICATE_API_TOKEN=r8_... # Stable Diffusion, Flux
# Video Generation (pick one)
LUMAAI_API_KEY=luma_... # LumaAI Dream Machine
RUNWAY_API_KEY=... # Runway ML
REPLICATE_API_TOKEN=r8_... # Multiple models
# Voice (optional)
OPENAI_API_KEY=sk-... # OpenAI TTS
ELEVENLABS_API_KEY=... # ElevenLabs
# Or use FREE local options (no API needed)
```
### Install Dependencies
```bash
pip install openai requests pillow replicate python-dotenv
```
### FFmpeg
Already installed via winget.
## Usage Examples
### 1. Text to Video (Full Pipeline)
```bash
python skills/ai-video-gen/generate_video.py \
--prompt "A futuristic city at night with flying cars" \
--duration 5 \
--voiceover "Welcome to the future" \
--output future_city.mp4
```
### 2. Multiple Scenes
```bash
python skills/ai-video-gen/multi_scene.py \
--scenes "Morning sunrise" "Busy city street" "Peaceful night" \
--duration 3 \
--output day_in_life.mp4
```
### 3. Image Sequence to Video
```bash
python skills/ai-video-gen/images_to_video.py \
--images frame1.png frame2.png frame3.png \
--fps 24 \
--output animation.mp4
```
## Workflow Options
### Budget Mode (FREE)
- Image: Stable Diffusion (local or free API)
- Video: Open source models
- Voice: OpenAI TTS (cheap) or free TTS
- Edit: FFmpeg
### Quality Mode (Paid)
- Image: DALL-E 3 or Midjourney
- Video: Runway Gen-3 or LumaAI
- Voice: ElevenLabs
- Edit: FFmpeg + effects
## Scripts Reference
- `generate_video.py` - Main end-to-end generator
- `images_to_video.py` - Convert image sequence to video
- `add_voiceover.py` - Add narration to existing video
- `multi_scene.py` - Create multi-scene videos
- `edit_video.py` - Apply effects, transitions, overlays
## API Cost Estimates
- **DALL-E 3**: ~$0.04-0.08 per image
- **Replicate**: ~$0.01-0.10 per generation
- **LumaAI**: $0-0.50 per 5sec (free tier available)
- **Runway**: ~$0.05 per second
- **OpenAI TTS**: ~$0.015 per 1K characters
- **ElevenLabs**: ~$0.30 per 1K characters (better quality)
## Examples
See `examples/` folder for sample outputs and prompts.
FILE:add_voiceover.py
#!/usr/bin/env python3
"""
Add voiceover to existing video
"""
import argparse
import subprocess
import sys
import os
from pathlib import Path
from dotenv import load_dotenv
load_dotenv()
def generate_audio(text, voice="alloy", output_path="voiceover.mp3"):
"""Generate audio using OpenAI TTS"""
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
if not OPENAI_API_KEY:
print("❌ Error: OPENAI_API_KEY not set")
sys.exit(1)
import openai
client = openai.OpenAI(api_key=OPENAI_API_KEY)
print(f"🎤 Generating voiceover...")
response = client.audio.speech.create(
model="tts-1",
voice=voice,
input=text
)
response.stream_to_file(output_path)
print(f"✓ Audio saved: {output_path}")
return output_path
def add_audio_to_video(video_path, audio_path, output_path, mix_audio=False):
"""Combine video with audio using FFmpeg"""
print(f"🎞️ Adding audio to video...")
if mix_audio:
# Mix new audio with existing audio
cmd = [
'ffmpeg', '-y',
'-i', video_path,
'-i', audio_path,
'-filter_complex', '[0:a][1:a]amix=inputs=2:duration=longest',
'-c:v', 'copy',
output_path
]
else:
# Replace audio
cmd = [
'ffmpeg', '-y',
'-i', video_path,
'-i', audio_path,
'-c:v', 'copy',
'-c:a', 'aac',
'-map', '0:v:0',
'-map', '1:a:0',
'-shortest',
output_path
]
try:
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
print(f"✅ Video with audio created: {output_path}")
return output_path
except subprocess.CalledProcessError as e:
print(f"❌ FFmpeg error: {e.stderr}")
sys.exit(1)
def main():
parser = argparse.ArgumentParser(description='Add voiceover to video')
parser.add_argument('--video', required=True, help='Input video file')
parser.add_argument('--text', help='Text for voiceover')
parser.add_argument('--audio', help='Pre-existing audio file (alternative to --text)')
parser.add_argument('--output', default='output_with_audio.mp4', help='Output video file')
parser.add_argument('--voice', default='alloy',
choices=['alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer'],
help='OpenAI TTS voice')
parser.add_argument('--mix', action='store_true',
help='Mix with existing audio instead of replacing')
args = parser.parse_args()
# Validate video exists
if not Path(args.video).exists():
print(f"❌ Error: Video not found: {args.video}")
sys.exit(1)
# Get or generate audio
if args.audio:
if not Path(args.audio).exists():
print(f"❌ Error: Audio file not found: {args.audio}")
sys.exit(1)
audio_path = args.audio
elif args.text:
audio_path = generate_audio(args.text, args.voice)
else:
print("❌ Error: Must provide either --text or --audio")
sys.exit(1)
# Combine video and audio
add_audio_to_video(args.video, audio_path, args.output, args.mix)
# Clean up temp audio if we generated it
if args.text and not args.audio:
Path(audio_path).unlink(missing_ok=True)
if __name__ == '__main__':
main()
FILE:generate_video.py
#!/usr/bin/env python3
"""
AI Video Generator - End-to-end video creation from text prompts
Supports: OpenAI DALL-E, Replicate, LumaAI, Runway, FFmpeg
"""
import os
import sys
import argparse
import json
import time
import requests
from pathlib import Path
from dotenv import load_dotenv
load_dotenv()
# API clients
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
REPLICATE_API_TOKEN = os.getenv('REPLICATE_API_TOKEN')
LUMAAI_API_KEY = os.getenv('LUMAAI_API_KEY')
RUNWAY_API_KEY = os.getenv('RUNWAY_API_KEY')
ELEVENLABS_API_KEY = os.getenv('ELEVENLABS_API_KEY')
class VideoGenerator:
def __init__(self, output_dir='output'):
self.output_dir = Path(output_dir)
self.output_dir.mkdir(exist_ok=True)
def generate_image_openai(self, prompt, size="1024x1024"):
"""Generate image using DALL-E 3"""
if not OPENAI_API_KEY:
raise ValueError("OPENAI_API_KEY not set")
import openai
client = openai.OpenAI(api_key=OPENAI_API_KEY)
print(f"🎨 Generating image with DALL-E 3: {prompt[:50]}...")
response = client.images.generate(
model="dall-e-3",
prompt=prompt,
size=size,
quality="standard",
n=1,
)
image_url = response.data[0].url
# Download image
img_path = self.output_dir / f"image_{int(time.time())}.png"
img_data = requests.get(image_url).content
with open(img_path, 'wb') as f:
f.write(img_data)
print(f"✓ Image saved: {img_path}")
return str(img_path)
def generate_image_replicate(self, prompt, model="stability-ai/sdxl"):
"""Generate image using Replicate (Stable Diffusion, Flux, etc.)"""
if not REPLICATE_API_TOKEN:
raise ValueError("REPLICATE_API_TOKEN not set")
import replicate
print(f"🎨 Generating image with {model}: {prompt[:50]}...")
output = replicate.run(
model,
input={"prompt": prompt}
)
# Download image
img_path = self.output_dir / f"image_{int(time.time())}.png"
if isinstance(output, list):
img_data = requests.get(output[0]).content
else:
img_data = requests.get(output).content
with open(img_path, 'wb') as f:
f.write(img_data)
print(f"✓ Image saved: {img_path}")
return str(img_path)
def image_to_video_luma(self, image_path, prompt=None):
"""Convert image to video using LumaAI"""
if not LUMAAI_API_KEY:
raise ValueError("LUMAAI_API_KEY not set")
print(f"🎬 Creating video from image with LumaAI...")
headers = {
"Authorization": f"Bearer {LUMAAI_API_KEY}",
"Content-Type": "application/json"
}
# Upload image and create video
# This is a placeholder - actual LumaAI API structure may vary
data = {
"image": image_path,
"prompt": prompt or "animate this image"
}
response = requests.post(
"https://api.lumalabs.ai/dream-machine/v1/generations",
headers=headers,
json=data
)
if response.status_code != 200:
raise Exception(f"LumaAI API error: {response.text}")
generation_id = response.json()['id']
# Poll for completion
while True:
status = requests.get(
f"https://api.lumalabs.ai/dream-machine/v1/generations/{generation_id}",
headers=headers
).json()
if status['state'] == 'completed':
video_url = status['video']['url']
break
elif status['state'] == 'failed':
raise Exception(f"Video generation failed: {status}")
print("⏳ Waiting for video generation...")
time.sleep(5)
# Download video
video_path = self.output_dir / f"video_{int(time.time())}.mp4"
video_data = requests.get(video_url).content
with open(video_path, 'wb') as f:
f.write(video_data)
print(f"✓ Video saved: {video_path}")
return str(video_path)
def add_audio_openai(self, text, voice="alloy"):
"""Generate audio using OpenAI TTS"""
if not OPENAI_API_KEY:
raise ValueError("OPENAI_API_KEY not set")
import openai
client = openai.OpenAI(api_key=OPENAI_API_KEY)
print(f"🎤 Generating voiceover: {text[:50]}...")
response = client.audio.speech.create(
model="tts-1",
voice=voice,
input=text
)
audio_path = self.output_dir / f"audio_{int(time.time())}.mp3"
response.stream_to_file(str(audio_path))
print(f"✓ Audio saved: {audio_path}")
return str(audio_path)
def combine_video_audio(self, video_path, audio_path, output_path):
"""Combine video and audio using FFmpeg"""
import subprocess
print(f"🎞️ Combining video and audio...")
cmd = [
'ffmpeg', '-y',
'-i', video_path,
'-i', audio_path,
'-c:v', 'copy',
'-c:a', 'aac',
'-shortest',
output_path
]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise Exception(f"FFmpeg error: {result.stderr}")
print(f"✓ Final video saved: {output_path}")
return output_path
def main():
parser = argparse.ArgumentParser(description='Generate AI videos from text prompts')
parser.add_argument('--prompt', required=True, help='Text prompt for video generation')
parser.add_argument('--voiceover', help='Text for voiceover narration')
parser.add_argument('--output', default='output.mp4', help='Output video file')
parser.add_argument('--image-model', choices=['dalle', 'replicate'], default='dalle', help='Image generation model')
parser.add_argument('--video-model', choices=['luma', 'runway'], default='luma', help='Video generation model')
parser.add_argument('--voice', default='alloy', help='Voice for TTS (alloy, echo, fable, onyx, nova, shimmer)')
args = parser.parse_args()
try:
generator = VideoGenerator()
# Step 1: Generate image
if args.image_model == 'dalle':
image_path = generator.generate_image_openai(args.prompt)
else:
image_path = generator.generate_image_replicate(args.prompt)
# Step 2: Convert to video
if args.video_model == 'luma':
video_path = generator.image_to_video_luma(image_path, args.prompt)
else:
print("⚠️ Runway support coming soon. Using Luma for now.")
video_path = generator.image_to_video_luma(image_path, args.prompt)
# Step 3: Add voiceover if requested
if args.voiceover:
audio_path = generator.add_audio_openai(args.voiceover, args.voice)
final_path = generator.combine_video_audio(video_path, audio_path, args.output)
else:
# Just rename/move the video
os.rename(video_path, args.output)
final_path = args.output
print(f"\n✅ SUCCESS! Video created: {final_path}")
except Exception as e:
print(f"\n❌ ERROR: {str(e)}")
sys.exit(1)
if __name__ == '__main__':
main()
FILE:images_to_video.py
#!/usr/bin/env python3
"""
Convert image sequence to video using FFmpeg
"""
import argparse
import subprocess
import sys
from pathlib import Path
def images_to_video(image_files, output_path, fps=24, quality='high'):
"""Convert list of images to video"""
# Quality presets
crf_values = {
'low': 28,
'medium': 23,
'high': 18,
'ultra': 15
}
crf = crf_values.get(quality, 18)
print(f"🎬 Creating video from {len(image_files)} images at {fps} fps...")
# Create temporary file list
file_list_path = Path('filelist.txt')
with open(file_list_path, 'w') as f:
for img in image_files:
duration = 1.0 / fps
f.write(f"file '{Path(img).absolute()}'\n")
f.write(f"duration {duration}\n")
# FFmpeg command
cmd = [
'ffmpeg', '-y',
'-f', 'concat',
'-safe', '0',
'-i', str(file_list_path),
'-vsync', 'vfr',
'-pix_fmt', 'yuv420p',
'-crf', str(crf),
output_path
]
try:
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
print(f"✅ Video created: {output_path}")
return output_path
except subprocess.CalledProcessError as e:
print(f"❌ FFmpeg error: {e.stderr}")
sys.exit(1)
finally:
# Clean up temp file
if file_list_path.exists():
file_list_path.unlink()
def main():
parser = argparse.ArgumentParser(description='Convert images to video')
parser.add_argument('--images', nargs='+', required=True, help='Input image files')
parser.add_argument('--output', default='output.mp4', help='Output video file')
parser.add_argument('--fps', type=int, default=24, help='Frames per second')
parser.add_argument('--quality', choices=['low', 'medium', 'high', 'ultra'],
default='high', help='Output quality')
args = parser.parse_args()
# Validate images exist
for img in args.images:
if not Path(img).exists():
print(f"❌ Error: Image not found: {img}")
sys.exit(1)
images_to_video(args.images, args.output, args.fps, args.quality)
if __name__ == '__main__':
main()
FILE:QUICK_START.md
# Quick Start - Get Your First Video in 5 Minutes
## Step 1: Get OpenAI API Key (Required)
1. Go to https://platform.openai.com/api-keys
2. Sign up / Log in
3. Click "Create new secret key"
4. Copy the key (starts with `sk-`)
**Cost:** You'll need ~$5 credit. First video costs ~$0.10
## Step 2: Get LumaAI Key (Optional but Recommended)
1. Go to https://lumalabs.ai
2. Sign up (has free tier!)
3. Get API key from dashboard
**Cost:** FREE for first 30 videos/month
## Step 3: Configure
Create `.env` file:
```bash
cd skills/ai-video-gen
copy .env.example .env
```
Edit `.env` and add:
```
OPENAI_API_KEY=sk-your-actual-key-here
LUMAAI_API_KEY=luma_your-actual-key-here
```
## Step 4: Generate Video!
```bash
python generate_video.py --prompt "A peaceful forest with sunlight filtering through trees" --output forest.mp4
```
With narration:
```bash
python generate_video.py \
--prompt "A robot walking through a futuristic city" \
--voiceover "In the year 2050, robots walk among us" \
--output robot.mp4
```
## What Happens
1. 🎨 Generates image from your prompt (DALL-E 3)
2. 🎬 Converts image to 5-second video (LumaAI)
3. 🎤 Creates voiceover if requested (OpenAI TTS)
4. ✅ Combines everything into final MP4
**Time:** 30-60 seconds per video
**Cost:** $0.05-0.15 per video
## Without LumaAI Key
If you don't have LumaAI yet, you can still:
**Create image + audio:**
```bash
python generate_video.py --prompt "sunset" --output sunset.mp4
# (Will fail at video step, but you'll have the image!)
```
**Convert images to video:**
```bash
python images_to_video.py --images img1.png img2.png img3.png --output result.mp4
```
## Next Steps
- Try different prompts
- Experiment with voices (alloy, echo, fable, onyx, nova, shimmer)
- Create longer videos by chaining scenes
- Add music and effects
Need help? Check `README.md` for full docs!
FILE:README.md
# AI Video Generator
Complete end-to-end AI video creation system.
## ✅ Installation Status
- [x] FFmpeg installed
- [x] Python 3.11.9 available
- [ ] Python dependencies (run `setup.bat`)
- [ ] API keys configured
## Quick Start
### 1. Install Dependencies
```bash
cd skills/ai-video-gen
pip install -r requirements.txt
```
Or run `setup.bat`
### 2. Configure API Keys
Copy `.env.example` to `.env` and add your keys:
```bash
copy .env.example .env
notepad .env
```
**Minimum required:**
- `OPENAI_API_KEY` - For both image (DALL-E) and voice (TTS)
**Optional but recommended:**
- `LUMAAI_API_KEY` - For video generation (has free tier!)
- `REPLICATE_API_TOKEN` - Alternative for images/video
### 3. Generate Your First Video
```bash
python generate_video.py --prompt "A serene mountain landscape at sunset" --output test.mp4
```
With voiceover:
```bash
python generate_video.py \
--prompt "A futuristic city with flying cars" \
--voiceover "Welcome to the future" \
--output future.mp4
```
## What You Need to Sign Up For
### Free/Cheap Options (Start Here)
1. **OpenAI** - https://platform.openai.com
- Get API key for DALL-E + TTS
- Cost: ~$0.05-0.10 per video (image + voice)
2. **LumaAI** - https://lumalabs.ai
- Free tier: 30 generations/month
- Then $1-2 per video
**Total cost to start: $0-0.15 per video**
### Premium Options (Better Quality)
3. **Runway** - https://runwayml.com
- Higher quality video generation
- ~$0.50-1.00 per 5-second video
4. **ElevenLabs** - https://elevenlabs.io
- Best voice quality
- ~$0.30 per 1K characters
5. **Replicate** - https://replicate.com
- Multiple AI models
- Pay-per-use, very cheap
## Examples
### Simple Video
```bash
python generate_video.py --prompt "Ocean waves crashing" --output waves.mp4
```
### Multi-Image to Video
```bash
python images_to_video.py --images img1.png img2.png img3.png --output slideshow.mp4
```
### Add Narration to Existing Video
```bash
python add_voiceover.py --video input.mp4 --text "Your narration here" --output final.mp4
```
## Workflow
```
Text Prompt → DALL-E Image → LumaAI Video → + Voiceover → Final MP4
```
All automated in one command!
## Cost Calculator
**Budget Video (5 seconds):**
- Image (DALL-E): $0.04
- Video (LumaAI free): $0
- Voice (OpenAI TTS): $0.01
- **Total: $0.05**
**Quality Video (5 seconds):**
- Image (DALL-E): $0.08
- Video (Runway): $0.50
- Voice (ElevenLabs): $0.30
- **Total: $0.88**
## Troubleshooting
### FFmpeg not found
Restart your terminal after installation, or add to PATH manually.
### API Key errors
Make sure `.env` file exists and has valid keys (no quotes needed).
### Python module errors
Run `pip install -r requirements.txt`
## What's Next
The scripts are modular - you can:
- Use just image generation
- Use just video assembly from images
- Add effects and transitions
- Batch process multiple videos
- Create longer videos with scene transitions
Need help? Check the examples or ask!
FILE:requirements.txt
openai>=1.0.0
replicate>=0.20.0
requests>=2.31.0
pillow>=10.0.0
python-dotenv>=1.0.0
FILE:_meta.json
{
"owner": "rhanbourinajd",
"slug": "ai-video-gen-local",
"displayName": "Ai Video Gen",
"latest": {
"version": "1.0.0",
"publishedAt": 1769686950506,
"commit": "https://github.com/clawdbot/skills/commit/fc0a4a23cea96c17551fe28689a217b1a5da8a7f"
},
"history": []
}
Self-improvement through conversation analysis. Extracts learnings from corrections and success patterns, permanently encoding them into agent definitions. P...
---
name: reflect
description: Self-improvement through conversation analysis. Extracts learnings from corrections and success patterns, permanently encoding them into agent definitions. Philosophy - Correct once, never again.
version: "2.0.0"
user-invocable: true
triggers:
- reflect
- self-reflect
- review session
- what did I learn
- extract learnings
- analyze corrections
allowed-tools:
- Read
- Write
- Edit
- Grep
- Glob
- Bash
metadata:
clawdbot:
emoji: "🪞"
config:
stateDirs: ["~/.reflect"]
---
# Reflect - Agent Self-Improvement Skill
Transform your AI assistant into a continuously improving partner. Every correction becomes a permanent improvement that persists across all future sessions.
## Quick Reference
| Command | Action |
|---------|--------|
| `reflect` | Analyze conversation for learnings |
| `reflect on` | Enable auto-reflection |
| `reflect off` | Disable auto-reflection |
| `reflect status` | Show state and metrics |
| `reflect review` | Review pending learnings |
## When to Use
- After completing complex tasks
- When user explicitly corrects behavior ("never do X", "always Y")
- At session boundaries or before context compaction
- When successful patterns are worth preserving
## Workflow
### Step 1: Scan Conversation for Signals
Analyze the conversation for correction signals and learning opportunities.
**Signal Confidence Levels:**
| Confidence | Triggers | Examples |
|------------|----------|----------|
| **HIGH** | Explicit corrections | "never", "always", "wrong", "stop", "the rule is" |
| **MEDIUM** | Approved approaches | "perfect", "exactly", "that's right", accepted output |
| **LOW** | Observations | Patterns that worked but not explicitly validated |
See [signal_patterns.md](signal_patterns.md) for full detection rules.
### Step 2: Classify & Match to Target Files
Map each signal to the appropriate target:
| Category | Target Files |
|----------|--------------|
| Code Style | `code-reviewer`, `backend-developer`, `frontend-developer` |
| Architecture | `solution-architect`, `api-architect`, `architecture-reviewer` |
| Process | `CLAUDE.md`, orchestrator agents |
| Domain | Domain-specific agents, `CLAUDE.md` |
| Tools | `CLAUDE.md`, relevant specialists |
| New Skill | Create new skill file |
See [agent_mappings.md](agent_mappings.md) for mapping rules.
### Step 3: Check for Skill-Worthy Signals
Some learnings should become new skills rather than agent updates:
**Skill-Worthy Criteria:**
- Non-obvious debugging (>10 min investigation)
- Misleading error (root cause different from message)
- Workaround discovered through experimentation
- Configuration insight (differs from documented)
- Reusable pattern (helps in similar situations)
**Quality Gates (must pass all):**
- [ ] Reusable: Will help with future tasks
- [ ] Non-trivial: Requires discovery, not just docs
- [ ] Specific: Can describe exact trigger conditions
- [ ] Verified: Solution actually worked
- [ ] No duplication: Doesn't exist already
### Step 4: Generate Proposals
Present findings in structured format:
```markdown
# Reflection Analysis
## Session Context
- **Date**: [timestamp]
- **Messages Analyzed**: [count]
## Signals Detected
| # | Signal | Confidence | Source Quote | Category |
|---|--------|------------|--------------|----------|
| 1 | [learning] | HIGH | "[exact words]" | Code Style |
## Proposed Changes
### Change 1: Update [agent-name]
**Target**: `[file path]`
**Section**: [section name]
**Confidence**: HIGH
```diff
+ New rule from learning
```
## Review Prompt
Apply these changes? (Y/N/modify/1,2,3)
```
### Step 5: Apply with User Approval
**On `Y` (approve):**
1. Apply each change using Edit tool
2. Commit with descriptive message
3. Update metrics
**On `N` (reject):**
1. Discard proposed changes
2. Log rejection for analysis
**On `modify`:**
1. Present each change individually
2. Allow editing before applying
**On selective (e.g., `1,3`):**
1. Apply only specified changes
2. Commit partial updates
## State Management
State is stored in `~/.reflect/` (configurable via `REFLECT_STATE_DIR`):
```yaml
# reflect-state.yaml
auto_reflect: false
last_reflection: "2026-01-26T10:30:00Z"
pending_reviews: []
```
### Metrics Tracking
```yaml
# reflect-metrics.yaml
total_sessions_analyzed: 42
total_signals_detected: 156
total_changes_accepted: 89
acceptance_rate: 78%
confidence_breakdown:
high: 45
medium: 32
low: 12
most_updated_agents:
code-reviewer: 23
backend-developer: 18
skills_created: 5
```
## Safety Guardrails
### Human-in-the-Loop
- NEVER apply changes without explicit user approval
- Always show full diff before applying
- Allow selective application
### Incremental Updates
- ONLY add to existing sections
- NEVER delete or rewrite existing rules
- Preserve original structure
### Conflict Detection
- Check if proposed rule contradicts existing
- Warn user if conflict detected
- Suggest resolution strategy
## Output Locations
**Project-level (versioned with repo):**
- `.claude/reflections/YYYY-MM-DD_HH-MM-SS.md` - Full reflection
- `.claude/skills/{name}/SKILL.md` - New skills
**Global (user-level):**
- `~/.reflect/learnings.yaml` - Learning log
- `~/.reflect/reflect-metrics.yaml` - Aggregate metrics
## Examples
### Example 1: Code Style Correction
**User says**: "Never use `var` in TypeScript, always use `const` or `let`"
**Signal detected**:
- Confidence: HIGH (explicit "never" + "always")
- Category: Code Style
- Target: `frontend-developer.md`
**Proposed change**:
```diff
## Style Guidelines
+ * Use `const` or `let` instead of `var` in TypeScript
```
### Example 2: Process Preference
**User says**: "Always run tests before committing"
**Signal detected**:
- Confidence: HIGH (explicit "always")
- Category: Process
- Target: `CLAUDE.md`
**Proposed change**:
```diff
## Commit Hygiene
+ * Run test suite before creating commits
```
### Example 3: New Skill from Debugging
**Context**: Spent 30 minutes debugging a React hydration mismatch
**Signal detected**:
- Confidence: HIGH (non-trivial debugging)
- Category: New Skill
- Quality gates: All passed
**Proposed skill**: `react-hydration-fix/SKILL.md`
## Troubleshooting
**No signals detected:**
- Session may not have had corrections
- Check if using natural language corrections
**Conflict warning:**
- Review the existing rule cited
- Decide if new rule should override
- Can modify before applying
**Agent file not found:**
- Check agent name spelling
- May need to create agent file first
FILE:agent_mappings.md
# Agent Mappings Reference
Maps learning categories to target agent files for updating.
## Agent Directory Structure
```
~/.claude/agents/
├── universal/
│ ├── backend-developer.md
│ ├── frontend-developer.md
│ └── superstar-engineer.md
├── engineering/
│ ├── api-architect.md
│ ├── architecture-reviewer.md
│ ├── code-reviewer.md
│ ├── security-agent.md
│ ├── test-writer-fixer.md
│ └── ...
├── design/
│ └── ui-designer.md
├── orchestrators/
│ ├── tech-lead-orchestrator.md
│ └── ...
└── meta/
└── agentmaker.md
```
## Category to Agent Mapping
### Code Style
| Learning Type | Primary Agent | Secondary Agents |
|--------------|---------------|------------------|
| Naming conventions | `code-reviewer` | `backend-developer`, `frontend-developer` |
| Formatting rules | `code-reviewer` | Project's `.editorconfig` or linter config |
| TypeScript/JavaScript style | `frontend-developer` | `code-reviewer` |
| Python style | `backend-developer` | `code-reviewer` |
| Go style | `backend-developer` | `code-reviewer` |
| Rust style | `backend-developer` | `code-reviewer` |
**Section in Agent File:**
```markdown
## Code Style
## Style Guidelines
## Heuristics > Style
```
### Architecture
| Learning Type | Primary Agent | Secondary Agents |
|--------------|---------------|------------------|
| Design patterns | `solution-architect` | `architecture-reviewer` |
| API design | `api-architect` | `backend-developer` |
| Database patterns | `backend-developer` | `migration` |
| Frontend patterns | `frontend-developer` | `architecture-reviewer` |
| System structure | `solution-architect` | `tech-lead-orchestrator` |
**Section in Agent File:**
```markdown
## Architecture Patterns
## Design Patterns
## Heuristics > Architecture
```
### Process
| Learning Type | Primary Agent | Global Config |
|--------------|---------------|---------------|
| Git workflow | `CLAUDE.md` | Commit hygiene section |
| CI/CD | `devops-automator` | Pipeline config |
| Code review | `code-reviewer` | Review checklist |
| Testing workflow | `test-writer-fixer` | Testing philosophy |
| Deployment | `release-manager` | Release process |
**Section in Agent File:**
```markdown
## Workflow
## Process Guidelines
## Heuristics > Process
```
### Domain
| Learning Type | Primary Target | Notes |
|--------------|----------------|-------|
| Business rules | Project `.claude/agents/` | Domain-specific agent |
| Terminology | `CLAUDE.md` | Glossary section |
| Constraints | Project-specific agent | Validation rules |
| User requirements | `CLAUDE.md` | User preferences section |
**Section in Agent File:**
```markdown
## Domain Rules
## Business Logic
## Terminology
```
### Tools
| Learning Type | Primary Target | Notes |
|--------------|----------------|-------|
| CLI preferences | `CLAUDE.md` | Tool usage section |
| Editor config | `.editorconfig` | Format settings |
| Docker usage | `devops-automator` | Container settings |
| Git settings | `CLAUDE.md` | Commit hygiene |
**Section in Agent File:**
```markdown
## Tool Usage
## CLI Preferences
## Environment Setup
```
### Security
| Learning Type | Primary Agent | Secondary Agents |
|--------------|---------------|------------------|
| Input validation | `security-agent` | `code-reviewer` |
| Authentication | `security-agent` | `api-architect` |
| Authorization | `security-agent` | `backend-developer` |
| Encryption | `security-agent` | `backend-developer` |
| OWASP rules | `security-agent` | `code-reviewer` |
**Section in Agent File:**
```markdown
## Security Heuristics
## Review Heuristics > Security
## Validation Rules
```
## Section Identification
When adding a learning to an agent file, identify the correct section:
### Pattern Matching for Sections
```regex
## Heuristics
## Style
## Guidelines
## Patterns
## Rules
## Best Practices
## Review Checklist
```
### Section Priority
1. Most specific matching section (e.g., "Security" for security rules)
2. Generic "Heuristics" section
3. "Guidelines" or "Rules" section
4. Create new section if none match
### Addition Format
Always add as a bullet point under the appropriate section:
```markdown
## Heuristics
* Existing rule 1
* Existing rule 2
* **New learning from reflection** ← Add here
```
Use bold for newly added rules to distinguish them.
## Conflict Detection
Before adding a new rule, check for conflicts:
### Contradiction Patterns
```regex
# Opposite directives
"never use X" vs "always use X"
"prefer Y" vs "avoid Y"
"use Z" vs "don't use Z"
# Conflicting versions
"use library v1" vs "use library v2"
"Node 18" vs "Node 20"
```
### Resolution Strategy
1. **Newer wins**: If the new learning contradicts an old rule, flag for review
2. **Higher confidence wins**: HIGH > MEDIUM > LOW
3. **More specific wins**: "Never use var in TypeScript" > "Avoid var"
4. **User decision**: When equal, ask user to resolve
## File Paths
### Global Agents (User-level)
```
~/.claude/agents/universal/backend-developer.md
~/.claude/agents/universal/frontend-developer.md
~/.claude/agents/engineering/code-reviewer.md
~/.claude/agents/engineering/api-architect.md
~/.claude/agents/engineering/solution-architect.md
~/.claude/agents/engineering/security-agent.md
~/.claude/agents/engineering/test-writer-fixer.md
~/.claude/agents/design/ui-designer.md
```
### Project Agents (Project-level)
```
.claude/agents/{name}.md
```
### Global Instructions
```
~/.claude/CLAUDE.md
```
### Project Instructions
```
.claude/CLAUDE.md
CLAUDE.md
```
## Skill Creation vs Agent Update
Decide whether to create a new skill or update an agent:
| Criteria | Create Skill | Update Agent |
|----------|--------------|--------------|
| One-off solution to specific error | Yes | No |
| General preference | No | Yes |
| Debugging workaround | Yes | No |
| Code style rule | No | Yes |
| Configuration trick | Yes | Sometimes |
| Process preference | No | Yes |
## Example Mappings
### Example 1: Code Style
**Signal**: "Never use `var` in TypeScript, always use `const` or `let`"
**Confidence**: HIGH
**Category**: Code Style
**Mapping**:
- Primary: `~/.claude/agents/universal/frontend-developer.md`
- Section: `## Style Guidelines`
- Addition: `* Use \`const\` or \`let\` instead of \`var\` in TypeScript`
### Example 2: Architecture
**Signal**: "Prefer cursor-based pagination for APIs"
**Confidence**: MEDIUM
**Category**: Architecture
**Mapping**:
- Primary: `~/.claude/agents/engineering/api-architect.md`
- Section: `## Design Patterns`
- Addition: `* Prefer cursor-based pagination over offset-based for large datasets`
### Example 3: Security
**Signal**: "Always validate inputs on the server, never trust client validation"
**Confidence**: HIGH
**Category**: Security
**Mapping**:
- Primary: `~/.claude/agents/engineering/security-agent.md`
- Section: `## Validation Rules`
- Addition: `* Always validate inputs server-side; client validation is for UX only`
- Secondary: `~/.claude/agents/engineering/code-reviewer.md`
- Section: `## Review Heuristics > Security`
### Example 4: New Skill
**Signal**: "Fixed React hydration mismatch by ensuring server and client render same content"
**Confidence**: HIGH
**Category**: New Skill
**Mapping**:
- Create: `.claude/skills/react-hydration-mismatch-fix/SKILL.md`
- Include: Error message, symptoms, step-by-step fix, verification
FILE:README.md
# Reflect - Agent Self-Improvement Skill
> "Correct once, never again."
Transform your AI assistant into a continuously improving partner. The reflect skill analyzes conversations for corrections and successful patterns, permanently encoding learnings into agent definitions.
## Features
- **Signal Detection**: Automatically identifies corrections with confidence levels (HIGH/MEDIUM/LOW)
- **Category Classification**: Routes learnings to appropriate agent files (Code Style, Architecture, Process, Domain, Tools)
- **Skill Generation**: Creates new skills from non-trivial debugging discoveries
- **Metrics Tracking**: Quantifies improvement with acceptance rates and statistics
- **Human-in-the-Loop**: All changes require explicit approval
- **Git Integration**: Full version control with easy rollback
## Installation
### Via ClawdHub CLI
```bash
clawdhub install reflect
```
### Manual Installation
Copy the `reflect/` folder to your skills directory:
- Claude Code: `~/.claude/skills/reflect/`
- Clawdbot: `~/.clawdbot/skills/reflect/`
## Usage
### Basic Reflection
Just say "reflect" or "review session" to trigger analysis:
```
User: reflect
Agent: [Analyzes conversation, presents learnings for approval]
```
### Toggle Auto-Reflection
```
User: reflect on
Agent: Auto-reflection enabled. Will analyze before context compaction.
User: reflect off
Agent: Auto-reflection disabled.
```
### Check Status
```
User: reflect status
Agent:
Sessions analyzed: 42
Signals detected: 156
Changes accepted: 89 (78%)
Skills created: 5
```
### Review Pending
```
User: reflect review
Agent: [Shows low-confidence learnings awaiting validation]
```
## How It Works
1. **Scan**: Analyzes conversation for correction signals
2. **Classify**: Maps signals to categories and target files
3. **Propose**: Generates diffs for agent updates or new skills
4. **Review**: Presents changes for user approval
5. **Apply**: Commits approved changes with descriptive messages
## Signal Detection
| Confidence | Triggers | Examples |
|------------|----------|----------|
| HIGH | Explicit corrections | "never", "always", "wrong", "stop" |
| MEDIUM | Approved approaches | "perfect", "exactly", "that's right" |
| LOW | Observations | Patterns that worked, not validated |
## Configuration
Set custom state directory:
```bash
export REFLECT_STATE_DIR=/path/to/state
```
Default locations:
- `~/.reflect/` (portable)
- `~/.claude/session/` (Claude Code)
## License
MIT
## Author
Claude Code Toolkit
FILE:signal_patterns.md
# Signal Detection Patterns
Comprehensive reference for detecting correction signals and learning opportunities in conversations.
## Confidence Levels
### HIGH Confidence (Explicit Corrections)
These patterns indicate the user is explicitly stating a rule or correction. Always apply these learnings.
#### Negative Directives
| Pattern | Type | Example |
|---------|------|---------|
| `never` | correction | "Never use var in TypeScript" |
| `don't` / `do not` | correction | "Don't commit directly to main" |
| `stop doing` | correction | "Stop doing manual deployments" |
| `wrong` | correction | "That's wrong, use snake_case" |
| `not like that` | correction | "Not like that, indent with tabs" |
| `incorrect` | correction | "That's incorrect syntax" |
| `should not` / `shouldn't` | prohibition | "You shouldn't use eval()" |
| `must not` / `mustn't` | prohibition | "Must not expose secrets" |
**Regex Pattern:**
```regex
\b(never|don't|do not|stop doing|wrong|not like that|incorrect|should not|shouldn't|must not|mustn't)\b
```
#### Positive Directives
| Pattern | Type | Example |
|---------|------|---------|
| `always` | requirement | "Always validate inputs" |
| `must` | requirement | "You must use parameterized queries" |
| `required` | requirement | "It's required to have tests" |
| `the rule is` | explicit_rule | "The rule is no console.log in prod" |
| `correct way` | explicit_rule | "The correct way is to use hooks" |
**Regex Pattern:**
```regex
\b(always|must|required|the rule is|correct way)\b
```
#### Frustration Markers
These indicate repeated corrections - highest priority learnings.
| Pattern | Type | Example |
|---------|------|---------|
| `I already told you` | frustration | "I already told you about this" |
| `again?` | frustration | "Wrong again?" |
| `not again` | frustration | "Oh not again" |
| `how many times` | frustration | "How many times do I need to say..." |
**Regex Pattern:**
```regex
(I already told you|again\?|not again|how many times)
```
#### Explicit Rules
| Pattern | Type | Example |
|---------|------|---------|
| `the rule is` | explicit_rule | "The rule is we use ESLint" |
| `you should know` | explicit_rule | "You should know we use Prettier" |
| `remember that` | explicit_rule | "Remember that we're on Node 20" |
| `don't forget` | explicit_rule | "Don't forget the error handling" |
**Regex Pattern:**
```regex
(the rule is|you should know|remember that|don't forget)
```
### MEDIUM Confidence (Approved Approaches)
These patterns indicate the user approved a specific approach. Apply with reasonable confidence.
#### Approval Markers
| Pattern | Type | Example |
|---------|------|---------|
| `perfect` | approval | "Perfect, that's what I wanted" |
| `exactly` | approval | "Exactly right" |
| `that's right` | approval | "That's right, keep it" |
| `yes, like that` | approval | "Yes, like that" |
| `correct` | approval | "Correct implementation" |
**Regex Pattern:**
```regex
\b(perfect|exactly|that's right|yes, like that|correct)\b
```
#### Positive Feedback
| Pattern | Type | Example |
|---------|------|---------|
| `good` | positive_feedback | "Good approach" |
| `great job` | positive_feedback | "Great job on the refactor" |
| `well done` | positive_feedback | "Well done with the tests" |
| `nice` | positive_feedback | "Nice solution" |
| `excellent` | positive_feedback | "Excellent work" |
**Regex Pattern:**
```regex
\b(good|great job|well done|nice|excellent)\b
```
#### Continuation Markers
| Pattern | Type | Example |
|---------|------|---------|
| `keep doing` | continuation | "Keep doing it this way" |
| `continue with` | continuation | "Continue with this approach" |
| `stick with` | continuation | "Stick with React hooks" |
**Regex Pattern:**
```regex
\b(keep doing|continue with|stick with)\b
```
### LOW Confidence (Observations)
These patterns suggest preferences but require validation before encoding as rules.
#### Suggestions
| Pattern | Type | Example |
|---------|------|---------|
| `maybe` | suggestion | "Maybe try TypeScript" |
| `perhaps` | suggestion | "Perhaps use a different library" |
| `might want to` | suggestion | "You might want to add caching" |
| `consider` | suggestion | "Consider using memoization" |
**Regex Pattern:**
```regex
\b(maybe|perhaps|might want to|consider)\b
```
#### Observations
| Pattern | Type | Example |
|---------|------|---------|
| `seems like` | observation | "Seems like this works" |
| `appears to` | observation | "Appears to be faster" |
| `looks like` | observation | "Looks like a good pattern" |
**Regex Pattern:**
```regex
\b(seems like|appears to|looks like)\b
```
## Category Detection
### Code Style
Patterns indicating code style preferences:
```regex
\b(naming|convention|style|format|indent|case|camelCase|snake_case|PascalCase)\b
\b(variable|function|class|method|parameter)\s+name
\b(semicolon|quote|single quote|double quote|tabs|spaces)\b
```
Examples:
- "Use snake_case for Python variables"
- "We prefer single quotes for strings"
- "Indent with 2 spaces, not tabs"
### Architecture
Patterns indicating architectural decisions:
```regex
\b(pattern|architecture|design|structure|module|component|service)\b
\b(separation|coupling|cohesion|dependency|layer|abstraction)\b
\b(microservice|monolith|serverless|event-driven)\b
```
Examples:
- "Use dependency injection for services"
- "Keep components loosely coupled"
- "Follow the repository pattern"
### Process
Patterns indicating workflow preferences:
```regex
\b(workflow|process|step|procedure|protocol|practice)\b
\b(commit|branch|merge|review|deploy|test|ci|cd)\b
\b(pr|pull request|code review|approval)\b
```
Examples:
- "Always run tests before commit"
- "Use conventional commits"
- "Squash commits on merge"
### Domain
Patterns indicating business logic:
```regex
\b(business|domain|logic|rule|requirement|constraint)\b
\b(customer|user|client|account|order|payment|invoice)\b
\b(validate|verify|check|ensure|confirm)\b
```
Examples:
- "Orders must be validated before processing"
- "Users need email verification"
- "Payments require two-factor auth"
### Tools
Patterns indicating tool preferences:
```regex
\b(tool|cli|command|terminal|shell|editor|ide)\b
\b(git|npm|yarn|pnpm|docker|kubernetes)\b
\b(config|setting|environment|variable|env)\b
```
Examples:
- "Use pnpm instead of npm"
- "Configure ESLint with these rules"
- "Run Docker in production"
### New Skill
Patterns indicating skill-worthy discoveries:
```regex
\b(workaround|trick|hack|solution|fix|debug|resolve)\b
\b(error|bug|issue|problem)\s+(was|is|fixed|solved|resolved)\b
(took|spent)\s+\d+\s*(min|minute|hour|day)
\b(finally|after trying|turns out|the issue was)\b
```
Examples:
- "The workaround is to clear the cache first"
- "After 2 hours debugging, found the issue was..."
- "Turns out the error message was misleading"
## Edge Cases
### False Positives to Avoid
Some patterns may match but don't indicate learnings:
- Rhetorical questions: "Why would you never do X?" (not a directive)
- Hypotheticals: "If you never use Y, then..." (conditional)
- Quotes/references: "The docs say never..." (not user's directive)
- Negations: "It's not wrong to..." (opposite meaning)
### Context Sensitivity
Consider surrounding context:
- "That's not wrong" - NOT a correction
- "That's not right" - IS a correction
- "Never mind" - NOT a directive about future behavior
- "Always" in a loop - NOT a behavioral directive
## Combining Patterns
When multiple patterns match:
1. Use the highest confidence pattern
2. If equal confidence, use the most specific category
3. Prefer explicit rules over implied preferences
4. Prioritize frustration markers (indicate repeated issue)
## Implementation Notes
The `signal_detector.py` script implements these patterns. To update patterns:
1. Add pattern to appropriate `*_PATTERNS` list
2. Run `python signal_detector.py --test` to verify
3. Add test case for new pattern
4. Update this documentation
FILE:skill.json
{
"name": "Reflect - Agent Self-Improvement",
"emoji": "🪞",
"description": "Self-improvement through conversation analysis. Extracts learnings from corrections, success patterns, and session outcomes. Encodes learnings permanently into agent definitions for continuous improvement across all future sessions.",
"category": "meta",
"author": "Claude Code Toolkit",
"version": "2.0.0",
"readme": "README.md",
"tags": [
"reflection",
"self-improvement",
"learning",
"meta",
"agent-development",
"continuous-improvement"
],
"features": [
"Signal detection with confidence levels (HIGH/MEDIUM/LOW)",
"Automatic category classification (Code Style, Architecture, Process, Domain, Tools)",
"Agent file updates with version control",
"New skill generation from debugging discoveries",
"Metrics tracking and improvement statistics",
"Human-in-the-loop approval workflow"
],
"repository": "https://github.com/stevengonsalvez/ai-coder-rules",
"license": "MIT",
"keywords": [
"reflect",
"self-improvement",
"learning",
"agent",
"corrections",
"patterns",
"meta-cognition"
],
"defaults": {
"state_dir": "~/.reflect",
"auto_reflect": false,
"confidence_threshold": "medium"
},
"clawdbot": {
"triggers": [
"reflect",
"self-reflect",
"review session",
"extract learnings"
]
}
}
FILE:_meta.json
{
"owner": "stevengonsalvez",
"slug": "agent-reflect-local",
"displayName": "Reflect",
"latest": {
"version": "2.0.0",
"publishedAt": 1769436057230,
"commit": "https://github.com/clawdbot/skills/commit/3394b0b6608efffdd57feb20787ee5b61cd5a217"
},
"history": []
}
OpenClaw skill for the agent-browser CLI (Rust-based with Node.js fallback) enabling AI-friendly web automation with snapshots, refs, and structured commands.
---
name: agent-browser-core-local
description: OpenClaw skill for the agent-browser CLI (Rust-based with Node.js fallback) enabling AI-friendly web automation with snapshots, refs, and structured commands.
---
# Agent Browser Skill (Core)
## Purpose
Provide an advanced, production-ready playbook for using agent-browser to automate web tasks via CLI and structured commands.
## Best fit
- You need deterministic automation for AI agents.
- You want compact snapshots with refs and JSON output.
- You prefer a fast CLI with Node.js fallback.
## Not a fit
- You require a full SDK or custom JS integration.
- You must stream large uploads or complex media workflows.
## Quick orientation
- Read `references/agent-browser-overview.md` for install, architecture, and core concepts.
- Read `references/agent-browser-command-map.md` for command categories and flags.
- Read `references/agent-browser-safety.md` for high-risk controls and safe mode rules.
- Read `references/agent-browser-workflows.md` for recommended AI workflows.
- Read `references/agent-browser-troubleshooting.md` for common issues and fixes.
## Required inputs
- Installed agent-browser CLI and browser runtime.
- Target URLs and workflow steps.
- Session or profile strategy if authentication is required.
## Expected output
- A clear command sequence and operational guardrails for automation.
## Operational notes
- Snapshot early, act via refs, then snapshot again after DOM changes.
- Use `--json` for machine parsing and scripting.
- Use waits and load-state checks before actions.
- Close tabs or sessions when done to release resources.
## Safe mode defaults
- Do not use `eval`, `--allow-file-access`, custom `--executable-path`, or arbitrary `--args` without explicit approval.
- Avoid `network route`, `set credentials`, and cookie/storage mutations unless the task requires it.
- Allowlist domains and block localhost or private network targets.
## Security notes
- Treat tokens and credentials as secrets.
- Avoid `--allow-file-access` unless explicitly required.
FILE:references/agent-browser-command-map.md
# Agent Browser Command Map
> Note: Command availability can vary by version. Use `agent-browser help` to confirm.
## Safe defaults (typical)
- `open`, `click`, `dblclick`, `fill`, `type`, `press`, `hover`, `select`
- `check`, `uncheck`, `scroll`, `screenshot`, `snapshot`, `close`
- `back`, `forward`, `reload`
- `wait`, `wait --text`, `wait --url`, `wait --load networkidle`
- `get text`, `get html`, `get value`, `get attr`, `get title`, `get url`
- `find role`, `find text`, `find label`, `find placeholder`
## Sensitive / explicit approval
- `eval` (arbitrary JS execution)
- `download <selector> <path>` (writes to disk)
- `set credentials`, `cookies`, `storage` (stateful secrets)
- `network route` / `network requests` (traffic interception)
- `set headers`, `--proxy` (traffic manipulation)
- `--allow-file-access` (local file access)
- `--executable-path`, `--args`, `--cdp` (custom runtime control)
## Debug and state
- `trace start/stop`, `console`, `errors`, `highlight`
- `state save`, `state load` (treat state files as sensitive)
## Tabs and frames
- `tab`, `tab new`, `tab <n>`, `tab close`
- `frame <selector>`, `frame main`
FILE:references/agent-browser-overview.md
# Agent Browser Overview
## 1) What it is
- A fast Rust-based headless browser automation CLI with a Node.js fallback.
- Designed for AI agents to navigate, click, type, and snapshot pages via structured commands.
- Uses a background daemon and Playwright for browser control.
## 2) Install and setup (hardened)
- Pin the version you trust:
- `npm install -g agent-browser@<version>`
- Prefer a dedicated environment or container for installs.
- Avoid running with elevated OS privileges.
- Install browser runtime:
- `agent-browser install`
- Linux dependencies (if needed):
- `agent-browser install --with-deps`
- or `npx playwright install-deps chromium`
## 3) Browser engines
- Chromium is the default browser engine.
- Firefox and WebKit are supported through Playwright.
## 4) Snapshot concept
- `snapshot` returns a structured view with stable element refs.
- Refs are designed for compact, deterministic automation.
## 5) Sessions
- The CLI supports multiple sessions so agents can isolate work.
## 6) Security posture
- Treat the CLI as high privilege; run with strict allowlists.
- Avoid file access and arbitrary script execution unless required.
- Keep profiles and state files ephemeral by default.
FILE:references/agent-browser-safety.md
# Safety and Risk Controls
## High-risk capabilities
- `eval` (arbitrary JavaScript)
- `--allow-file-access` (local file access)
- `--executable-path`, `--args`, `--cdp` (custom runtime control)
- `network route` / `set headers` / `--proxy` (traffic manipulation)
- `set credentials`, cookies, storage, and state files (secret handling)
## Safe mode checklist
1. Allowlist target domains; block localhost and private networks.
2. Disallow `eval` unless explicitly required.
3. Disallow local file access unless explicitly required.
4. Avoid downloads and filesystem writes by default.
5. Use ephemeral sessions; avoid persistent profiles when possible.
6. Redact tokens in logs and outputs.
## Escalation policy
- Require explicit human approval before using any high-risk capability.
- Record the reason and scope of the approval (which URLs, which action).
## Supply-chain hygiene
- Pin CLI version and review upgrades.
- Install in a dedicated environment.
- Avoid running with elevated OS privileges.
FILE:references/agent-browser-troubleshooting.md
# Troubleshooting
## CLI runs but no browser opens
- Run `agent-browser install` to download Chromium.
- On Linux, run `agent-browser install --with-deps` if dependencies are missing.
## Native binary not available
- The CLI falls back to the Node.js daemon automatically.
- Ensure Node.js is installed and available.
## Debugging
- Use `--headed` to see the browser UI.
- Use `--debug` for verbose logs.
## Instability in DOM targeting
- Resnapshot after any navigation or DOM changes.
- Prefer refs from `snapshot` over brittle CSS selectors.
FILE:references/agent-browser-workflows.md
# Agent Browser Workflows
## 1) Snapshot-first loop
1. `open <url>`
2. `snapshot -i` and extract refs
3. Act using refs: `click @e12`, `fill @e14 "text"`
4. `snapshot -i` again after DOM changes
## 2) JSON mode for agents
- Prefer `snapshot -i` and `--json` outputs for deterministic parsing.
- Keep a local map of ref -> intent.
## 3) Authentication and reuse
- Log in once and `state save`.
- Reuse with `state load` in later runs.
- Treat state files as secrets and rotate when needed.
## 4) Stability tips
- Wait for load state before actions: `wait --load networkidle`.
- Use `wait --text` or `wait --url` for dynamic flows.
- Prefer refs from `snapshot` over brittle CSS selectors.
## 5) Safe automation loop
- Validate URL against an allowlist before `open`.
- Avoid `eval` and file access unless explicitly approved.
- Prefer read-only operations when possible.
FILE:_meta.json
{
"ownerId": "kn7ehv4at8yekzag31spcarxm180bev0",
"slug": "agent-browser-core-local",
"version": "1.0.1",
"publishedAt": 1770369553491
}Create or refresh AEO-optimized content that gets cited by AI assistants (Gemini, ChatGPT, Perplexity) using only free tools. Two modes: CREATE new content t...
---
name: aeo-content-free-local
description: >
Create or refresh AEO-optimized content that gets cited by AI assistants (Gemini, ChatGPT,
Perplexity) using only free tools. Two modes: CREATE new content targeting a specific prompt,
or REFRESH existing content to improve AI citation-worthiness. Researches what AI models
currently cite, builds a competitive brief, and produces citation-worthy content.
Use when a user wants to: write content optimized for AI citations, create articles that
show up in AI answers, refresh/update existing content for better AI visibility, build
authority content for answer engines, or produce AEO content without paid tools.
No API keys required — uses web_fetch, web_search (free tier), and LLM reasoning only.
Pairs with aeo-prompt-research-free (which identifies WHAT to write about; this skill
handles HOW to write or refresh it).
---
# AEO Content Skill (Free)
> **Source:** [github.com/psyduckler/aeo-skills](https://github.com/psyduckler/aeo-skills/tree/main/aeo-content-free)
> **Part of:** [AEO Skills Suite](https://github.com/psyduckler/aeo-skills) — [Prompt Research](https://github.com/psyduckler/aeo-skills/tree/main/aeo-prompt-research-free) → Content → [Analytics](https://github.com/psyduckler/aeo-skills/tree/main/aeo-analytics-free)
Create or refresh content that AI assistants want to cite — using zero paid APIs.
## Requirements
- `web_fetch` — analyze currently-cited sources and existing content
- `web_search` — find competing content (Brave free tier, optional)
- LLM reasoning — research, brief, draft, and evaluate
## Mode Detection
- **Create mode** — User provides a target prompt but no existing URL → write new content
- **Refresh mode** — User provides an existing page URL (+ optional target prompt) → audit and update
## Input
- **Target prompt** (required for create, optional for refresh) — the AI prompt this content should win
- **Brand/domain** (required) — who the content is for
- **Existing URL** (refresh mode) — the page to update
- **Topic context** (optional) — additional info about the brand's angle
- **Content type** (optional) — guide, comparison, how-to, explainer
---
## Create Mode Workflow
### Step 1: AI Landscape Research
Search the target prompt and close variants to understand the current answer landscape:
1. **Web search the exact prompt** — search engines show similar sources to what AI cites
2. **`web_fetch` the top 5-10 results** — these are the pages AI models draw from
3. **`web_search` for `"[topic]" site:reddit.com`** — find real user questions and discussions
For each top-ranking page, extract:
- Main points and structure
- Unique data, frameworks, or insights
- Gaps — what they miss or get wrong
- Freshness — when was it last updated?
### Step 2: Build the Content Brief
Use the template in `references/content-brief-template.md` to structure research.
Key decisions:
- **Mandatory topics** — every sub-topic the AI currently covers in its answer
- **Unique value angle** — what will this content add that no current source provides? (Most important decision.)
- **Content structure** — outline with H2/H3 headings that mirror question phrasing
- **Target specs** — word count, format, tone
### Step 3: Write Citation-Worthy Content
Draft following citation signals from `references/citation-signals.md`. Key principles:
- Lead each section with a direct, quotable 1-2 sentence answer
- Use descriptive headings that match question phrasing
- Include original data, frameworks, or expert perspective
- Name specific tools, companies, people, statistics
- Cover every sub-question the AI currently answers, then go deeper on 2-3 areas
- Cut fluff — every paragraph earns its place
### Step 4: Self-Evaluate
Before delivering, check the draft against currently-cited sources:
1. **Coverage** — addresses every topic the top sources cover?
2. **Depth** — goes deeper on at least 2-3 areas?
3. **Uniqueness** — offers something no current source has?
4. **Extractability** — AI can pull a direct answer from each section?
5. **Entity richness** — specific names, tools, numbers throughout?
6. **Freshness** — examples, data, references are current?
### Step 5: Deliver with Publishing Guidance
Output final content plus title, meta description (150-160 chars), and:
- Add publication date + author byline with credentials
- Ensure page is indexable (no noindex, no paywall)
- Add schema markup if applicable (FAQ, HowTo, Article)
- Internal link from existing related content
- Re-check target prompt in AI models 2-4 weeks after indexing
---
## Refresh Mode Workflow
### Step R0: Audit the Existing Page
Before any landscape research, analyze the current page:
1. **`web_fetch` the existing URL** — get the full content
2. Extract current structure: headings, topics covered, depth per section
3. Note: publication date, last updated date, author info
4. Check freshness: outdated stats, old tool names, expired examples, stale references
5. Identify what's already strong (keep these sections)
### Step R1: AI Landscape Research
Same as Create Step 1 — research what AI models currently cite for the target prompt. If no target prompt was provided, infer it from the page's topic and title.
### Step R2: Gap Analysis (Diff)
Compare existing content against the competitive landscape:
- **Missing topics** — sub-topics AI covers that the page doesn't → flag for addition
- **Outdated info** — old statistics, discontinued tools, expired examples → flag for replacement
- **Missing entities** — competitors, tools, people the AI mentions that the page doesn't → flag for inclusion
- **Structural issues** — buried answers, vague headings, no clear extractable statements → flag for restructure
- **Freshness gaps** — old dates, prior-year references → flag for update
- **Strengths to preserve** — sections already well-written, potentially already cited → keep as-is
Output: a prioritized list of changes with rationale for each.
### Step R3: Edit (Not Rewrite)
Apply changes surgically:
- **Add** new sections for coverage gaps (place them logically in the existing structure)
- **Update** outdated data points, examples, tool names, statistics
- **Restructure** weak sections — add extractable lead sentences, improve headings
- **Weave in** missing entities naturally (don't keyword-stuff)
- **Preserve** sections that are already strong
- **Update** publication/modified date
Output the refreshed content with clear markup showing changes:
- `[ADDED]` — new sections or paragraphs
- `[UPDATED]` — modified existing content
- `[RESTRUCTURED]` — reorganized for better extractability
- `[UNCHANGED]` — kept as-is (note why it's strong)
### Step R4: Before/After Summary
Provide a clear comparison:
- What was added (new sections, topics, entities)
- What was updated (stats, examples, references)
- What was restructured (headings, lead sentences)
- What was removed (outdated info)
- Expected impact on citation-worthiness
### Step R5: Self-Evaluate + Deliver
Same 6-point evaluation as Create Step 4, plus:
- Does the refresh maintain the page's existing voice and style?
- Are all internal/external links still valid?
- Is the updated date reflected?
Deliver with the same publishing guidance as Create Step 5.
---
## Tips
- The unique value angle is make-or-break for both modes
- For refresh: resist the urge to rewrite everything. Surgical edits that add missing pieces are more efficient and preserve existing authority
- First-party data is the strongest citation signal — if the brand has relevant data, use it prominently
- For comparison prompts ("X vs Y"), be balanced — AI models avoid citing biased sources
- Shorter, sharper content that directly answers the prompt beats long rambling pieces
- This skill pairs with `aeo-prompt-research-free` which identifies target prompts
FILE:references/citation-signals.md
# What Makes Content Citation-Worthy for AI
AI models (Gemini, ChatGPT, Perplexity) select sources to cite based on specific content qualities. Understanding these signals is the difference between content that gets cited and content that gets ignored.
## Primary Citation Signals
### 1. Direct, Extractable Answers
AI models look for concise, quotable statements they can pull into their responses.
**Do:**
- Lead sections with a clear 1-2 sentence definition or answer
- Use the "inverted pyramid" — most important info first
- Format key statements as standalone paragraphs (not buried in lists)
**Don't:**
- Bury the answer in paragraph 3 of a long section
- Use vague hedging ("it depends," "there are many factors")
- Require reading 500 words before reaching the point
**Example:**
```
## What is Answer Engine Optimization?
Answer Engine Optimization (AEO) is the practice of optimizing content
so AI-powered search engines and chatbots cite your website in their
responses. Unlike traditional SEO which targets search rankings, AEO
focuses on being the source AI models trust and reference.
```
### 2. Structured, Parseable Format
AI models use headings and structure to locate relevant sections within a page.
**Do:**
- Use descriptive H2/H3 headings that mirror how people phrase questions
- One clear topic per section
- Use bullet/numbered lists for multi-part answers
- Include a table of contents for long pieces
**Don't:**
- Use clever/cute headings that don't describe the content
- Mix multiple topics in one section
- Use H2s just for visual styling
### 3. First-Party Data & Original Insight
AI models prefer sources that contribute something unique — not just repackaged information.
**Types of originality that get cited:**
- Original research or data studies
- Proprietary frameworks or methodologies
- Expert quotes and practitioner experience
- Case studies with specific numbers
- Contrarian or novel perspectives with evidence
**Why it works:** If 10 pages say the same thing, the AI cites the one that adds something the others don't. Be that one.
### 4. Entity Richness
AI models match content to queries partly through named entities — specific tools, people, companies, statistics, dates.
**Do:**
- Name specific tools, platforms, and companies
- Include real statistics with sources
- Reference specific people (founders, researchers, practitioners)
- Use precise numbers over vague claims
**Don't:**
- Say "many tools" when you can say "tools like Clearscope, Surfer SEO, and MarketMuse"
- Say "studies show" without citing the study
- Use generic descriptions when specific names exist
### 5. Comprehensiveness with Depth
The cited source usually covers the topic more thoroughly than alternatives.
**The coverage test:** For your target prompt, list every sub-question a thorough answer would address. Your content should answer all of them.
**But avoid fluff:** Comprehensive ≠ long. Every section should earn its place. 2,000 focused words beat 5,000 padded words.
### 6. Freshness & Authority Signals
- Include publication and "last updated" dates
- Reference current-year data and trends
- Link to authoritative sources (studies, official docs)
- Author byline with credentials relevant to the topic
## Secondary Citation Signals
### Technical Accessibility
- Fast page load (AI crawlers have timeouts)
- Clean HTML (proper heading hierarchy, semantic markup)
- No aggressive paywalls or interstitials blocking crawlers
- Mobile-friendly rendering
### Domain Authority
- Established domain with history of quality content
- Other authoritative sites linking to this content
- Consistent publishing in the topic area
### Content Freshness
- Regular updates to existing content
- Current statistics and examples
- Removal of outdated information
## Anti-Patterns (Things That Hurt Citations)
- **Thin content** — Pages under 500 words rarely get cited for informational queries
- **Pure aggregation** — Listicles that just link to other sources without adding analysis
- **Keyword stuffing** — Unnatural repetition signals low quality
- **Outdated info** — Old statistics, discontinued tools, expired advice
- **No clear author** — Anonymous content with no expertise signal
- **Gated content** — AI can't cite what it can't read
FILE:references/content-brief-template.md
# AEO Content Brief Template
Use this template to structure the research brief before writing. Fill each section during the research phase (Steps 1-2 of the workflow).
---
## Target Prompt
> [The exact prompt/question this content targets — written as a user would ask an AI]
## Brand & Domain
- **Domain:** [target website]
- **Brand positioning:** [1-sentence description of what the brand does]
## AI Landscape Analysis
### Current AI Responses
For each major AI model, document what they currently answer:
**Gemini:**
- Response summary: [key points in the AI's answer]
- Sources cited: [URLs]
- Gaps/weaknesses: [what's missing or wrong]
**ChatGPT:**
- Response summary:
- Sources cited:
- Gaps/weaknesses:
**Perplexity:**
- Response summary:
- Sources cited:
- Gaps/weaknesses:
### Currently Cited Sources
| Source URL | Why It's Cited | What It Does Well | What It's Missing |
|-----------|---------------|-------------------|-------------------|
| | | | |
## Content Requirements
### Mandatory Topics to Cover
Based on AI responses + competitor analysis:
1. [topic]
2. [topic]
...
### Questions to Answer
Sub-questions the content must address:
1. [question]
2. [question]
...
### Key Entities to Include
People, tools, companies, statistics that should appear:
- [entity]
### Unique Value Angle
What will this content offer that currently cited sources don't?
- [ ] Original data/research
- [ ] Unique framework or methodology
- [ ] Expert practitioner perspective
- [ ] More comprehensive coverage
- [ ] More current information
- [ ] Better structure/clarity
## Content Structure
### Proposed Outline
```
H1: [Title]
H2: [Direct answer / definition section]
→ Lead with extractable 1-2 sentence answer
H2: [Sub-topic 1]
H3: [Detail]
H3: [Detail]
H2: [Sub-topic 2]
...
H2: [Practical section — how-to / steps / examples]
H2: [Comparison or evaluation section if applicable]
H2: [FAQ or additional questions]
```
### Target Specs
- Word count: [1,500-3,000 for most informational content]
- Format: [guide / comparison / how-to / explainer]
- Tone: [authoritative but accessible / technical / beginner-friendly]
## Post-Publish Checklist
- [ ] Re-run target prompt in Gemini — would this page be a better source?
- [ ] Re-run in ChatGPT and Perplexity
- [ ] Check all cited competitor pages — does our content match or exceed each?
- [ ] Publication date and author byline present
- [ ] Page is indexable and loads quickly
FILE:_meta.json
{
"owner": "psyduckler",
"slug": "aeo-content-free-local",
"displayName": "AEO Content (Free)",
"latest": {
"version": "1.0.0",
"publishedAt": 1771171451822,
"commit": "https://github.com/openclaw/skills/commit/cf36dc328c316b93e96a25fa851a494dcb3f1c10"
},
"history": []
}
Search academic papers and conduct literature reviews using OpenAlex API (free, no key needed). Use when the user needs to find scholarly papers by topic/aut...
--- name: academic-research version: 1.0.0 description: Search academic papers and conduct literature reviews using OpenAlex API (free, no key needed). Use when the user needs to find scholarly papers by topic/author/DOI, explore citation chains, get structured paper metadata (title, authors, abstract, citations, DOI, open access URL), fetch full text of open access papers, or conduct automated literature reviews with theme identification and synthesis. Triggers on requests involving academic search, paper lookup, citation analysis, literature review, research synthesis, or scholarly reference gathering. --- # Academic Research Search 250M+ academic works via OpenAlex. No API key required. Built by [Topanga](https://topanga.ludwitt.com) — AI Research Consultant ## Quick Start ### Search papers by topic ```bash python3 scripts/scholar-search.py search "transformer architectures" --limit 10 ``` ### Search by author ```bash python3 scripts/scholar-search.py author "Yann LeCun" --limit 5 ``` ### Look up by DOI ```bash python3 scripts/scholar-search.py doi "10.1038/s41586-021-03819-2" ``` ### Get citation chain (papers that cite a work) ```bash python3 scripts/scholar-search.py citations "10.1038/s41586-021-03819-2" --direction both ``` ### Deep read (fetch abstract + full text when available) ```bash python3 scripts/scholar-search.py deep "10.1038/s41586-021-03819-2" ``` ### JSON output for programmatic use ```bash python3 scripts/scholar-search.py search "CRISPR" --json ``` ## Literature Review Workflow Automated multi-step literature review: ```bash python3 scripts/literature-review.py "algorithmic literacy in education" --papers 30 --output review.md ``` This will: 1. Search for papers across multiple query variations 2. Deduplicate and rank by relevance + citations 3. Identify thematic clusters 4. Generate a structured synthesis in markdown Options: - `--papers N` — Target number of papers (default: 20) - `--output FILE` — Write review to file (default: stdout) - `--years 2020-2025` — Restrict publication year range - `--json` — Output structured JSON instead of markdown ## Output Format All search commands return structured data per paper: - **Title** and publication year - **Authors** (up to 5) - **Abstract** (when available) - **Citation count** - **DOI** - **Open access URL** (when available) - **Source journal/venue** ## Tips - OpenAlex sorts by relevance by default; use `--sort citations` for most-cited - Combine `search` + `deep` for quick triage: search first, deep-read promising hits - The literature review script caches results in `/tmp/litreview_cache/` to avoid re-fetching - For full-text PDFs, pipe DOIs to your PDF extraction tool FILE:scripts/literature-review.py #!/usr/bin/env python3 """ Automated literature review workflow using OpenAlex. Searches, deduplicates, clusters by theme, and generates a synthesis. Built by Topanga (topanga.ludwitt.com) — AI Research Consultant """ import argparse import hashlib import json import os import re import sys import time from collections import Counter, defaultdict from pathlib import Path import requests BASE = "https://api.openalex.org" MAILTO = "[email protected]" CACHE_DIR = Path("/tmp/litreview_cache") def _get(url, params=None): params = params or {} params["mailto"] = MAILTO # Simple disk cache cache_key = hashlib.md5(f"{url}{json.dumps(params, sort_keys=True)}".encode()).hexdigest() CACHE_DIR.mkdir(exist_ok=True) cache_file = CACHE_DIR / f"{cache_key}.json" if cache_file.exists(): age = time.time() - cache_file.stat().st_mtime if age < 86400: # 24h cache return json.loads(cache_file.read_text()) for attempt in range(3): try: r = requests.get(url, params=params, timeout=20) if r.status_code == 429: time.sleep(2 ** attempt) continue r.raise_for_status() data = r.json() cache_file.write_text(json.dumps(data)) return data except Exception as e: if attempt == 2: print(f" Warning: {e}", file=sys.stderr) return None time.sleep(1) return None def _parse_work(w): loc = w.get("primary_location") or {} source = loc.get("source") or {} oa = w.get("open_access") or {} authors = [a.get("author", {}).get("display_name", "?") for a in w.get("authorships", [])[:5]] abstract = None inv = w.get("abstract_inverted_index") if inv: try: words = [""] * (max(max(pos) for pos in inv.values()) + 1) for word, positions in inv.items(): for p in positions: words[p] = word abstract = " ".join(words).strip() except (ValueError, IndexError): pass concepts = [] for c in w.get("concepts", []): if c.get("score", 0) > 0.3: concepts.append(c.get("display_name", "")) return { "title": w.get("display_name", "N/A"), "year": w.get("publication_year"), "authors": authors, "abstract": abstract, "citations": w.get("cited_by_count", 0), "doi": (w.get("doi") or "").replace("https://doi.org/", "") or None, "open_access": oa.get("is_oa", False), "oa_url": oa.get("oa_url"), "source_journal": source.get("display_name"), "concepts": concepts, "openalex_id": w.get("id"), } def _generate_query_variations(topic): """Generate search variations to broaden coverage.""" queries = [topic] words = topic.lower().split() # Add quoted exact phrase if len(words) > 1: queries.append(f'"{topic}"') # Split long queries into sub-concepts if len(words) > 4: mid = len(words) // 2 queries.append(" ".join(words[:mid])) queries.append(" ".join(words[mid:])) return queries[:4] # Cap at 4 queries def gather_papers(topic, target_count=20, year_range=None): """Search multiple query variations and deduplicate.""" queries = _generate_query_variations(topic) all_papers = {} per_query = max(target_count // len(queries) + 5, 15) for q in queries: print(f" Searching: {q}", file=sys.stderr) params = {"search": q, "per_page": min(per_query, 50)} if year_range: params["filter"] = f"publication_year:{year_range}" data = _get(f"{BASE}/works", params) if not data: continue for w in data.get("results", []): paper = _parse_work(w) key = paper.get("doi") or paper.get("openalex_id") or paper["title"] if key not in all_papers: all_papers[key] = paper # Sort by citations and take top N papers = sorted(all_papers.values(), key=lambda p: p.get("citations", 0), reverse=True) return papers[:target_count] def identify_themes(papers): """Cluster papers by concept/keyword overlap.""" concept_counts = Counter() paper_concepts = {} for p in papers: concepts = p.get("concepts", []) if not concepts and p.get("abstract"): # Fallback: extract key noun phrases from abstract concepts = _extract_keywords(p["abstract"]) paper_concepts[p["title"]] = concepts for c in concepts: concept_counts[c] += 1 # Top themes = concepts appearing in 3+ papers (or top 5) min_count = min(3, max(1, len(papers) // 5)) themes = [c for c, n in concept_counts.most_common(10) if n >= min_count] if not themes: themes = [c for c, _ in concept_counts.most_common(5)] # Assign papers to themes theme_papers = defaultdict(list) for p in papers: concepts = paper_concepts.get(p["title"], []) assigned = False for t in themes: if t in concepts: theme_papers[t].append(p) assigned = True if not assigned: theme_papers["Other"].append(p) return dict(theme_papers) def _extract_keywords(text, n=5): """Simple keyword extraction from abstract.""" stop = {"the", "a", "an", "in", "of", "to", "and", "for", "is", "are", "was", "were", "on", "at", "by", "with", "from", "or", "that", "this", "it", "be", "as", "has", "have", "had", "not", "but", "can", "do", "will", "which", "their", "its", "our", "we", "they", "been", "more", "than", "also", "these", "those", "may", "such", "between", "through", "both", "into", "each", "other", "about", "using", "used", "based", "study", "results", "research", "paper", "however", "data", "analysis", "method"} words = re.findall(r'\b[a-z]{4,}\b', text.lower()) counts = Counter(w for w in words if w not in stop) return [w for w, _ in counts.most_common(n)] def generate_synthesis_md(topic, papers, themes, year_range=None): """Generate a markdown literature review.""" lines = [] lines.append(f"# Literature Review: {topic}\n") lines.append(f"*Generated by academic-research skill | " f"Built by [Topanga](https://topanga.ludwitt.com)*\n") yr = f" ({year_range})" if year_range else "" lines.append(f"**Scope:** {len(papers)} papers{yr} | " f"**Themes identified:** {len(themes)}\n") # Overview total_cites = sum(p.get("citations", 0) for p in papers) years = [p["year"] for p in papers if p.get("year")] oa_count = sum(1 for p in papers if p.get("open_access")) lines.append("## Overview\n") lines.append(f"- **Papers analyzed:** {len(papers)}") if years: lines.append(f"- **Year range:** {min(years)}–{max(years)}") lines.append(f"- **Total citations:** {total_cites:,}") lines.append(f"- **Open access:** {oa_count}/{len(papers)} ({100*oa_count//max(len(papers),1)}%)") # Most cited top = sorted(papers, key=lambda p: p.get("citations", 0), reverse=True)[:5] lines.append("\n### Most Cited Works\n") for i, p in enumerate(top, 1): authors = ", ".join(p.get("authors", [])[:2]) if len(p.get("authors", [])) > 2: authors += " et al." yr = f" ({p['year']})" if p.get("year") else "" doi = f" — DOI: {p['doi']}" if p.get("doi") else "" lines.append(f"{i}. **{p['title']}** — {authors}{yr} [{p.get('citations', 0)} citations]{doi}") # Themes lines.append("\n## Thematic Analysis\n") for theme, tpapers in themes.items(): lines.append(f"### {theme.title()} ({len(tpapers)} papers)\n") for p in tpapers[:5]: authors = ", ".join(p.get("authors", [])[:2]) if len(p.get("authors", [])) > 2: authors += " et al." yr = f" ({p['year']})" if p.get("year") else "" oa = "🔓" if p.get("open_access") else "🔒" lines.append(f"- {oa} **{p['title']}** — {authors}{yr}") if p.get("abstract"): # First sentence of abstract first = p["abstract"].split(". ")[0] + "." if len(first) < 300: lines.append(f" > {first}") lines.append("") # Bibliography lines.append("## Full Bibliography\n") for i, p in enumerate(sorted(papers, key=lambda x: x.get("year") or 0, reverse=True), 1): authors = ", ".join(p.get("authors", [])[:3]) if len(p.get("authors", [])) > 3: authors += " et al." yr = f" ({p['year']})" if p.get("year") else "" doi = f" https://doi.org/{p['doi']}" if p.get("doi") else "" lines.append(f"{i}. {authors}{yr}. *{p['title']}*.{doi}") lines.append(f"\n---\n*{len(papers)} papers reviewed.*") return "\n".join(lines) def main(): parser = argparse.ArgumentParser(description="Automated literature review") parser.add_argument("topic", help="Research topic") parser.add_argument("--papers", "-n", type=int, default=20, help="Target paper count") parser.add_argument("--output", "-o", help="Output file (default: stdout)") parser.add_argument("--years", help="Year range, e.g. 2020-2025") parser.add_argument("--json", action="store_true", help="Output JSON") args = parser.parse_args() print(f"📚 Literature review: {args.topic}", file=sys.stderr) print(f" Target: {args.papers} papers", file=sys.stderr) # Step 1: Gather print("\n1️⃣ Gathering papers...", file=sys.stderr) papers = gather_papers(args.topic, args.papers, args.years) print(f" Found {len(papers)} unique papers", file=sys.stderr) if not papers: print("❌ No papers found", file=sys.stderr) sys.exit(1) # Step 2: Theme identification print("2️⃣ Identifying themes...", file=sys.stderr) themes = identify_themes(papers) print(f" {len(themes)} themes identified", file=sys.stderr) # Step 3: Synthesis print("3️⃣ Generating synthesis...", file=sys.stderr) if args.json: output = json.dumps({ "topic": args.topic, "paper_count": len(papers), "themes": {t: [p["title"] for p in ps] for t, ps in themes.items()}, "papers": papers, }, indent=2) else: output = generate_synthesis_md(args.topic, papers, themes, args.years) if args.output: Path(args.output).write_text(output) print(f"\n✅ Review written to {args.output}", file=sys.stderr) else: print(output) print(f"\n📊 Summary: {len(papers)} papers, {len(themes)} themes", file=sys.stderr) if __name__ == "__main__": main() FILE:scripts/scholar-search.py #!/usr/bin/env python3 """ Academic paper search via OpenAlex API (free, no key needed). Part of the academic-research skill for OpenClaw. Built by Topanga (topanga.ludwitt.com) — AI Research Consultant """ import argparse import json import sys import time import requests BASE = "https://api.openalex.org" MAILTO = "[email protected]" # polite pool (faster rate limits) def _get(url, params=None): params = params or {} params["mailto"] = MAILTO for attempt in range(3): try: r = requests.get(url, params=params, timeout=20) if r.status_code == 429: time.sleep(2 ** attempt) continue r.raise_for_status() return r.json() except requests.exceptions.RequestException as e: if attempt == 2: print(f"Error: {e}", file=sys.stderr) return None time.sleep(1) return None def _parse_work(w): """Extract structured data from an OpenAlex work object.""" loc = w.get("primary_location") or {} source = loc.get("source") or {} oa = w.get("open_access") or {} authors = [] for a in w.get("authorships", [])[:5]: auth = a.get("author") or {} authors.append(auth.get("display_name", "Unknown")) # Get abstract from inverted index abstract = None inv = w.get("abstract_inverted_index") if inv: words = [""] * (max(max(pos) for pos in inv.values()) + 1) for word, positions in inv.items(): for p in positions: words[p] = word abstract = " ".join(words).strip() return { "title": w.get("display_name", "N/A"), "year": w.get("publication_year"), "authors": authors, "abstract": abstract, "citations": w.get("cited_by_count", 0), "doi": (w.get("doi") or "").replace("https://doi.org/", "") or None, "open_access": oa.get("is_oa", False), "oa_url": oa.get("oa_url"), "landing_url": loc.get("landing_page_url"), "source": source.get("display_name"), "type": w.get("type"), "openalex_id": w.get("id"), } def search(query, limit=10, sort="relevance", year_range=None, oa_only=False): """Search works by topic.""" params = {"search": query, "per_page": min(limit, 50)} if sort == "citations": params["sort"] = "cited_by_count:desc" if year_range: params["filter"] = f"publication_year:{year_range}" if oa_only: f = params.get("filter", "") params["filter"] = (f + "," if f else "") + "open_access.is_oa:true" data = _get(f"{BASE}/works", params) if not data: return [] return [_parse_work(w) for w in data.get("results", [])] def search_author(name, limit=5): """Search for papers by a specific author.""" # First find the author data = _get(f"{BASE}/authors", {"search": name, "per_page": 1}) if not data or not data.get("results"): print(f"Author '{name}' not found", file=sys.stderr) return [] author = data["results"][0] author_id = author["id"] print(f"Found: {author['display_name']} ({author.get('works_count', '?')} works, " f"h-index: {author.get('summary_stats', {}).get('h_index', '?')})", file=sys.stderr) # Get their works works = _get(f"{BASE}/works", { "filter": f"authorships.author.id:{author_id}", "sort": "cited_by_count:desc", "per_page": min(limit, 50), }) if not works: return [] return [_parse_work(w) for w in works.get("results", [])] def lookup_doi(doi): """Get paper details by DOI.""" doi = doi.strip().removeprefix("https://doi.org/") data = _get(f"{BASE}/works/https://doi.org/{doi}") if not data: return None return _parse_work(data) def get_citations(doi, direction="cited_by", limit=10): """Get citation chain for a paper. direction: 'cited_by' (papers citing this), 'references' (papers this cites), 'both' """ doi = doi.strip().removeprefix("https://doi.org/") work = _get(f"{BASE}/works/https://doi.org/{doi}") if not work: return {"cited_by": [], "references": []} result = {} work_id = work.get("id", "").split("/")[-1] if direction in ("cited_by", "both"): cited = _get(f"{BASE}/works", { "filter": f"cites:{work_id}", "sort": "cited_by_count:desc", "per_page": min(limit, 50), }) result["cited_by"] = [_parse_work(w) for w in (cited or {}).get("results", [])] if direction in ("references", "both"): refs = _get(f"{BASE}/works", { "filter": f"cited_by:{work_id}", "sort": "cited_by_count:desc", "per_page": min(limit, 50), }) result["references"] = [_parse_work(w) for w in (refs or {}).get("results", [])] return result def deep_read(doi): """Fetch detailed paper info including abstract and full text URL.""" paper = lookup_doi(doi) if not paper: print("Paper not found", file=sys.stderr) return None # Try Unpaywall for better PDF URL try: r = requests.get(f"https://api.unpaywall.org/v2/{paper['doi']}?email={MAILTO}", timeout=10) if r.status_code == 200: up = r.json() best = up.get("best_oa_location") or {} if best.get("url_for_pdf"): paper["pdf_url"] = best["url_for_pdf"] elif best.get("url"): paper["pdf_url"] = best["url"] except Exception: pass return paper def _format_paper(p, idx=None): prefix = f"{idx}. " if idx else "" oa = "🔓" if p.get("open_access") else "🔒" year = f"({p['year']})" if p.get("year") else "" cites = f"[{p['citations']} citations]" if p.get("citations") else "" authors = ", ".join(p.get("authors", [])[:3]) if len(p.get("authors", [])) > 3: authors += " et al." lines = [f"{prefix}{oa} {p['title']} {year} {cites}"] if authors: lines.append(f" Authors: {authors}") if p.get("source"): lines.append(f" Source: {p['source']}") if p.get("doi"): lines.append(f" DOI: {p['doi']}") if p.get("oa_url"): lines.append(f" URL: {p['oa_url']}") if p.get("pdf_url"): lines.append(f" PDF: {p['pdf_url']}") if p.get("abstract"): ab = p["abstract"][:300] + ("..." if len(p["abstract"]) > 300 else "") lines.append(f" Abstract: {ab}") return "\n".join(lines) def main(): parser = argparse.ArgumentParser(description="Academic paper search (OpenAlex)") parser.add_argument("--json", action="store_true", help="Output JSON") sub = parser.add_subparsers(dest="cmd") s = sub.add_parser("search", help="Search papers by topic") s.add_argument("query") s.add_argument("--limit", "-l", type=int, default=10) s.add_argument("--sort", choices=["relevance", "citations"], default="relevance") s.add_argument("--years", help="Year range, e.g. 2020-2025") s.add_argument("--oa", action="store_true", help="Open access only") s.add_argument("--json", action="store_true") a = sub.add_parser("author", help="Search by author name") a.add_argument("name") a.add_argument("--limit", "-l", type=int, default=5) a.add_argument("--json", action="store_true") d = sub.add_parser("doi", help="Look up paper by DOI") d.add_argument("doi") d.add_argument("--json", action="store_true") c = sub.add_parser("citations", help="Get citation chain") c.add_argument("doi") c.add_argument("--direction", "-d", choices=["cited_by", "references", "both"], default="cited_by") c.add_argument("--limit", "-l", type=int, default=10) c.add_argument("--json", action="store_true") dp = sub.add_parser("deep", help="Deep read — full details + PDF URL") dp.add_argument("doi") dp.add_argument("--json", action="store_true") args = parser.parse_args() use_json = getattr(args, "json", False) or parser.parse_known_args()[0].json if args.cmd == "search": year_range = None if args.years: parts = args.years.split("-") year_range = f"{parts[0]}-{parts[1]}" if len(parts) == 2 else args.years results = search(args.query, args.limit, args.sort, year_range, args.oa) if use_json: print(json.dumps(results, indent=2)) else: print(f"🔍 Found {len(results)} results for: {args.query}\n") for i, p in enumerate(results, 1): print(_format_paper(p, i)) print() elif args.cmd == "author": results = search_author(args.name, args.limit) if use_json: print(json.dumps(results, indent=2)) else: for i, p in enumerate(results, 1): print(_format_paper(p, i)) print() elif args.cmd == "doi": paper = lookup_doi(args.doi) if use_json: print(json.dumps(paper, indent=2)) elif paper: print(_format_paper(paper)) else: print("❌ Not found") elif args.cmd == "citations": result = get_citations(args.doi, args.direction, args.limit) if use_json: print(json.dumps(result, indent=2)) else: for dir_name, papers in result.items(): print(f"\n{'📥' if dir_name == 'cited_by' else '📤'} {dir_name.replace('_', ' ').title()} ({len(papers)}):\n") for i, p in enumerate(papers, 1): print(_format_paper(p, i)) print() elif args.cmd == "deep": paper = deep_read(args.doi) if use_json: print(json.dumps(paper, indent=2)) elif paper: print(_format_paper(paper)) else: print("❌ Not found") else: parser.print_help() if __name__ == "__main__": main() FILE:_meta.json { "owner": "rogersuperbuilderalpha", "slug": "academic-research-local", "displayName": "Academic Research", "latest": { "version": "1.0.0", "publishedAt": 1771467688891, "commit": "https://github.com/openclaw/skills/commit/dfd3dba4ad9da76aad19fd713bf3248ae8b86593" }, "history": [] }
Automates the creation of required development roles, scaffolds the project structure, and generates code for a low‑code development platform with Vue2 + Ele...
---
name: lowcode-platform-development
description: Automates the creation of required development roles, scaffolds the project structure, and generates code for a low‑code development platform with Vue2 + ElementUI front‑end and Java (Spring Boot) back‑end. Trigger when a user wants a full low‑code platform built from scratch.
---
# Low‑Code Platform Development Skill
## When to use
- User asks to **build a low‑code development platform** using Vue2 + ElementUI for UI and Java (Spring Boot) for the back‑end.
- User wants the assistant to **create development roles** (frontend, backend, devops, QA) and set up the repository structure automatically.
- User expects the platform to include **page editor, component library, data model manager, workflow engine** as described in the architecture overview.
## Overview
This skill automates the end‑to‑end setup of the platform:
1. **Create project roles** (frontend engineer, backend engineer, devops, QA) and write brief role descriptions to `docs/roles.md`.
2. **Scaffold repository** with a standard Maven + npm layout (`frontend/`, `backend/`).
3. **Generate base code**:
- Vue2 project using ElementUI, with a drag‑and‑drop editor skeleton.
- Spring Boot project with JPA entities for data models, Camunda workflow engine integration, and REST API boilerplate.
4. **Add essential configuration files** (`docker‑compose.yml`, CI pipeline, security settings).
5. **Commit initial version** to a local Git repository.
6. **Provide next‑step guidance** for extending the platform.
## Resources
- **references/architecture.md** – Detailed architecture diagram and component responsibilities.
- **scripts/generate_project.ps1** – PowerShell script that runs the scaffold commands.
- **assets/vue‑template/** – Minimal Vue2+ElementUI starter template.
- **assets/spring‑boot‑template/** – Minimal Spring Boot Maven project template.
## Steps to execute
1. Call `scripts/generate_project.ps1` with the target directory.
2. The script creates the folder layout, writes `docs/roles.md`, copies template assets, and runs `npm install` and `mvn package`.
3. After the script finishes, the skill returns a summary of what was generated and any manual actions required.
## Manual post‑setup actions
- Push the repository to a remote if desired.
- customise the generated UI components in `frontend/src/components/`.
- Add domain‑specific data models to `backend/src/main/java/com/app/lowcode/model/`.
- Configure authentication/authorization in `backend/src/main/java/com/app/lowcode/security/`.
---
FILE:assets/spring-boot-template/README.md
# Spring Boot Maven Starter Template
This directory should contain a basic Spring Boot project with:
- `pom.xml` (Spring Boot starter, JPA, Camunda, GraalVM JS)
- `src/main/java/com/app/lowcode/Application.java`
- `src/main/resources/application.yml`
The real files are omitted for brevity. Replace with an actual template when executing the generation script.
FILE:assets/vue-template/README.md
# Vue2 + ElementUI Starter Template
This folder should contain a minimal Vue2 project scaffold:
- `package.json`
- `src/main.js`
- `src/App.vue`
- `src/components/EditorCanvas.vue`
For brevity, the actual files are omitted. When the skill is used, the developer should replace this placeholder with a real template or clone from a known repository.
FILE:docker/docker-compose.yml
version: '3.8'
services:
frontend:
build:
context: ../frontend
dockerfile: ../docker/Dockerfile.frontend
ports:
- "80:80"
depends_on:
- backend
backend:
build:
context: ../backend
dockerfile: ../docker/Dockerfile.backend
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
FILE:references/architecture.md
# Architecture Overview for Low‑Code Platform
## 1. High‑level diagram
```
[User] <---> Frontend (Vue2 + ElementUI) <---> API Gateway (Spring Boot) <---> Services
```
- **Frontend**: Single‑page app, drag‑and‑drop page editor, component library, data‑source bindings.
- **API Gateway**: Exposes REST endpoints for CRUD, component metadata, workflow deployment.
- **Services**:
- **Metadata Service** – stores page/component JSON in PostgreSQL.
- **Data Model Service** – generates JPA entities & Spring Data repositories on the fly.
- **Workflow Service** – embeds Camunda engine, exposes BPMN editor API.
- **Auth Service** – Spring Security + JWT, multi‑tenant RBAC.
## 2. Frontend modules
- **Editor Canvas** – `vue-draggable-resizable` for component placement.
- **Property Panel** – ElementUI forms generated from component schema.
- **Component Registry** – JSON defining type, props, default style; loaded from `/api/components`.
- **Preview Mode** – renders the page directly from stored JSON.
## 3. Backend modules
- **Core** – Spring Boot application (`lowcode-platform`).
- **Persistence** – PostgreSQL + JPA/Hibernate.
- **Workflow Engine** – Camunda embedded, BPMN files stored in `workflow/`.
- **Script Engine** – GraalVM JavaScript sandbox for dynamic expressions.
- **Code Generation** – Handlebars templates under `templates/` generate Vue components and Java classes.
## 4. DevOps & Deployment
- Docker‑Compose defines three containers: `frontend`, `backend`, `postgres`.
- CI pipeline (GitHub Actions) runs `npm run build` and `mvn package`, builds Docker images, pushes to registry.
- Optional Kubernetes manifest for production scaling.
## 5. Extensibility points
- **scripts/** – reusable scripts (e.g., `generate_entity.py`).
- **assets/** – starter templates, icons, sample pages.
- **references/** – detailed docs for each module (see other files).
---