feat: consolidate docs, backend/session infra, and settings updates
This commit is contained in:
1084
docs/user-facing/AGENTIC_VIBE_IMPLEMENTATION_PLAN.md
Normal file
1084
docs/user-facing/AGENTIC_VIBE_IMPLEMENTATION_PLAN.md
Normal file
File diff suppressed because it is too large
Load Diff
294
docs/user-facing/IMAGE_GENERATION_README.md
Normal file
294
docs/user-facing/IMAGE_GENERATION_README.md
Normal file
@@ -0,0 +1,294 @@
|
||||
# Image Generation Feature - Testing Guide
|
||||
|
||||
## ✅ Implementation Complete
|
||||
|
||||
The AI-powered image generation feature has been fully implemented and is ready for testing.
|
||||
|
||||
---
|
||||
|
||||
## 🎯 What Was Implemented
|
||||
|
||||
### Backend (PHP)
|
||||
1. **Database Tables**
|
||||
- `wp_wpaw_images` - Stores image recommendations from the agent
|
||||
- `wp_wpaw_images_variants` - Stores generated image variants
|
||||
|
||||
2. **Image Manager Class** (`includes/class-image-manager.php`)
|
||||
- Article analysis for optimal image placement
|
||||
- Model-specific prompt generation (FLUX.2 klein, Riverflow V2 Max, FLUX.2 max)
|
||||
- Image variant generation via OpenRouter API
|
||||
- WordPress Media Library integration
|
||||
- Automatic temp file cleanup (7+ days)
|
||||
|
||||
3. **REST API Endpoints**
|
||||
- `GET /wp-json/wp-agentic-writer/v1/image-recommendations/{post_id}`
|
||||
- `POST /wp-json/wp-agentic-writer/v1/generate-image`
|
||||
- `POST /wp-json/wp-agentic-writer/v1/commit-image`
|
||||
|
||||
4. **OpenRouter Provider Updates**
|
||||
- Proper image generation API implementation
|
||||
- Support for variant count, size, quality parameters
|
||||
|
||||
5. **Cron Job**
|
||||
- Daily cleanup of temp images older than 7 days
|
||||
- Automatic scheduling on plugin activation
|
||||
|
||||
### Frontend (JavaScript)
|
||||
1. **Image Modal Component** (`assets/js/image-modal.js`)
|
||||
- Image recommendation review
|
||||
- Editable prompts and alt text
|
||||
- User-controlled variant count (1-3 per image)
|
||||
- Cost preview before generation
|
||||
- Variant selection interface
|
||||
- Automatic Gutenberg block updates
|
||||
|
||||
### Settings
|
||||
1. **Updated Model Presets**
|
||||
- **Budget:** FLUX.2 klein ($0.014-0.042/image)
|
||||
- **Balanced:** Riverflow V2 Max ($0.03/image)
|
||||
- **Premium:** FLUX.2 max ($0.07-0.21/image)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 How to Test
|
||||
|
||||
### Step 1: Activate/Reactivate Plugin
|
||||
|
||||
**Important:** You need to reactivate the plugin to create the new database tables.
|
||||
|
||||
1. Go to **Plugins** in WordPress admin
|
||||
2. **Deactivate** WP Agentic Writer
|
||||
3. **Activate** WP Agentic Writer again
|
||||
|
||||
This will:
|
||||
- Create `wp_wpaw_images` table
|
||||
- Create `wp_wpaw_images_variants` table
|
||||
- Create `/wp-content/uploads/wpaw/` directory
|
||||
- Schedule daily cleanup cron job
|
||||
|
||||
**Alternative:** Run the SQL manually in phpMyAdmin/Adminer using `CREATE_TABLE.sql`
|
||||
|
||||
### Step 2: Verify Tables Created
|
||||
|
||||
Run this in phpMyAdmin or Adminer:
|
||||
|
||||
```sql
|
||||
SHOW TABLES LIKE 'wp_wpaw_%';
|
||||
```
|
||||
|
||||
You should see:
|
||||
- `wp_wpaw_cost_tracking`
|
||||
- `wp_wpaw_images`
|
||||
- `wp_wpaw_images_variants`
|
||||
|
||||
### Step 3: Configure Image Model
|
||||
|
||||
1. Go to **Settings → WP Agentic Writer**
|
||||
2. Click **Models** tab
|
||||
3. Choose a preset or manually select an image model:
|
||||
- Budget: `black-forest-labs/flux.2-klein`
|
||||
- Balanced: `sourceful/riverflow-v2-max` (recommended)
|
||||
- Premium: `black-forest-labs/flux.2-max`
|
||||
|
||||
### Step 4: Test Image Generation Flow
|
||||
|
||||
#### A. Create a New Post
|
||||
|
||||
1. Create a new post in WordPress
|
||||
2. Open the **WP Agentic Writer** sidebar
|
||||
3. Enable **Include Images** in the Config tab (should be on by default)
|
||||
|
||||
#### B. Generate Article with Images
|
||||
|
||||
1. In Chat mode, discuss your article topic
|
||||
2. Switch to Planning mode
|
||||
3. Click **Generate Plan**
|
||||
4. Click **Execute Plan**
|
||||
|
||||
The agent will:
|
||||
- Write the article content
|
||||
- Insert `[IMAGE: description]` placeholders
|
||||
- These will be converted to empty `core/image` blocks with `data-agent-image-id` attributes
|
||||
|
||||
#### C. Review Image Recommendations (Manual Trigger for Now)
|
||||
|
||||
**Note:** The automatic modal trigger after article generation needs to be integrated into `sidebar.js`. For now, you can test the backend directly:
|
||||
|
||||
**Test Backend API:**
|
||||
|
||||
```bash
|
||||
# Get image recommendations
|
||||
curl -X GET "http://your-site.local/wp-json/wp-agentic-writer/v1/image-recommendations/{POST_ID}" \
|
||||
-H "X-WP-Nonce: YOUR_NONCE"
|
||||
|
||||
# Generate image variants
|
||||
curl -X POST "http://your-site.local/wp-json/wp-agentic-writer/v1/generate-image" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-WP-Nonce: YOUR_NONCE" \
|
||||
-d '{
|
||||
"post_id": 123,
|
||||
"agent_image_id": "img_hero_1",
|
||||
"prompt": "Modern dashboard interface with blue colors",
|
||||
"variant_count": 2
|
||||
}'
|
||||
|
||||
# Commit image to Media Library
|
||||
curl -X POST "http://your-site.local/wp-json/wp-agentic-writer/v1/commit-image" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-WP-Nonce: YOUR_NONCE" \
|
||||
-d '{
|
||||
"post_id": 123,
|
||||
"agent_image_id": "img_hero_1",
|
||||
"variant_id": 1,
|
||||
"alt": "Dashboard showing workflow automation"
|
||||
}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 File Structure
|
||||
|
||||
```
|
||||
wp-agentic-writer/
|
||||
├── includes/
|
||||
│ ├── class-image-manager.php ✅ NEW - Core image generation logic
|
||||
│ ├── class-gutenberg-sidebar.php ✅ UPDATED - Added REST endpoints
|
||||
│ ├── class-openrouter-provider.php ✅ UPDATED - Proper image API
|
||||
│ └── class-settings.php ✅ UPDATED - New image model presets
|
||||
├── assets/
|
||||
│ └── js/
|
||||
│ └── image-modal.js ✅ NEW - Frontend modal component
|
||||
├── wp-agentic-writer.php ✅ UPDATED - Activation & cron hooks
|
||||
├── CREATE_TABLE.sql ✅ UPDATED - Added image tables
|
||||
└── IMAGE_GENERATION_IMPLEMENTATION_PLAN.md ✅ Complete implementation plan
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Debugging
|
||||
|
||||
### Check if Tables Exist
|
||||
|
||||
```sql
|
||||
DESCRIBE wp_wpaw_images;
|
||||
DESCRIBE wp_wpaw_images_variants;
|
||||
```
|
||||
|
||||
### Check Temp Directory
|
||||
|
||||
```bash
|
||||
ls -la /path/to/wp-content/uploads/wpaw/
|
||||
```
|
||||
|
||||
Should exist with `.htaccess` and `index.php` security files.
|
||||
|
||||
### Check Cron Job Scheduled
|
||||
|
||||
```php
|
||||
// Add to functions.php temporarily
|
||||
var_dump(wp_next_scheduled('wpaw_cleanup_temp_images'));
|
||||
```
|
||||
|
||||
Should return a timestamp.
|
||||
|
||||
### Check REST API Endpoints
|
||||
|
||||
Visit: `http://your-site.local/wp-json/wp-agentic-writer/v1/`
|
||||
|
||||
Should list the new endpoints:
|
||||
- `/image-recommendations/(?P<post_id>\d+)`
|
||||
- `/generate-image`
|
||||
- `/commit-image`
|
||||
|
||||
### Enable Debug Logging
|
||||
|
||||
Add to `wp-config.php`:
|
||||
|
||||
```php
|
||||
define('WP_DEBUG', true);
|
||||
define('WP_DEBUG_LOG', true);
|
||||
define('WP_DEBUG_DISPLAY', false);
|
||||
```
|
||||
|
||||
Check `/wp-content/debug.log` for errors.
|
||||
|
||||
---
|
||||
|
||||
## 💰 Cost Estimates
|
||||
|
||||
### Per Image (with 2 variants)
|
||||
|
||||
| Preset | Model | Cost per Image | Cost for 3 Images |
|
||||
|--------|-------|----------------|-------------------|
|
||||
| Budget | FLUX.2 klein | ~$0.04 | ~$0.12 |
|
||||
| Balanced | Riverflow V2 Max | ~$0.06 | ~$0.18 |
|
||||
| Premium | FLUX.2 max | ~$0.30 | ~$0.90 |
|
||||
|
||||
### User Controls
|
||||
|
||||
- **Variant count:** 1-3 per image (user selectable)
|
||||
- **Image selection:** Generate only selected images
|
||||
- **Skip option:** Can skip all images
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Known Limitations
|
||||
|
||||
1. **Modal Integration:** The image modal needs to be triggered from `sidebar.js` after article execution completes. Currently, the modal component exists but needs integration.
|
||||
|
||||
2. **Image Block Detection:** The system looks for `core/image` blocks with `data-agent-image-id` attribute to update them after image selection.
|
||||
|
||||
3. **OpenRouter API:** Requires OpenRouter API key with image generation access. Not all models may be available depending on your OpenRouter account.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Next Steps for Full Integration
|
||||
|
||||
To complete the user-facing feature, you need to:
|
||||
|
||||
1. **Trigger Modal After Article Generation**
|
||||
- In `sidebar.js`, after article execution completes
|
||||
- Check if images were recommended
|
||||
- Open the image review modal
|
||||
|
||||
2. **Add "Generate Images" Button**
|
||||
- Add a button in the sidebar to manually trigger image generation
|
||||
- Useful for regenerating or adding images later
|
||||
|
||||
3. **Block Toolbar Integration**
|
||||
- Add "Generate Image" button to empty image blocks
|
||||
- Allow regeneration of existing images
|
||||
|
||||
---
|
||||
|
||||
## ✅ Testing Checklist
|
||||
|
||||
- [ ] Plugin reactivated successfully
|
||||
- [ ] Database tables created
|
||||
- [ ] Temp directory exists with security files
|
||||
- [ ] Cron job scheduled
|
||||
- [ ] Image model configured in settings
|
||||
- [ ] Article generated with `[IMAGE: ...]` placeholders
|
||||
- [ ] Image blocks created in Gutenberg
|
||||
- [ ] REST API endpoints accessible
|
||||
- [ ] Can generate image variants via API
|
||||
- [ ] Can commit image to Media Library
|
||||
- [ ] Temp files cleaned up after 7 days
|
||||
|
||||
---
|
||||
|
||||
## 📞 Support
|
||||
|
||||
If you encounter issues:
|
||||
|
||||
1. Check `wp-content/debug.log` for PHP errors
|
||||
2. Check browser console for JavaScript errors
|
||||
3. Verify OpenRouter API key has image generation access
|
||||
4. Ensure database tables were created
|
||||
5. Check file permissions on `/wp-content/uploads/wpaw/`
|
||||
|
||||
---
|
||||
|
||||
**Implementation Date:** January 28, 2026
|
||||
**Version:** 1.0
|
||||
**Status:** ✅ Ready for Testing
|
||||
121
docs/user-facing/README.md
Normal file
121
docs/user-facing/README.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# WP Agentic Writer
|
||||
|
||||
**Plan-first AI writing workflow for WordPress**
|
||||
|
||||
A WordPress plugin that transforms how developers and technical writers create blog posts. Instead of the traditional "blank page → write → edit" workflow, it implements a multi-phase agentic AI workflow:
|
||||
|
||||
```
|
||||
Scribble (Ideas) → Research → Plan (Outline) → Execute (Write) → Discussion/Revise
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
### 5-Phase Workflow
|
||||
|
||||
1. **Brainstorm & Scribble** - Share raw ideas, code snippets, or vague topics
|
||||
2. **Research** - Optional web search for current information (via OpenRouter)
|
||||
3. **Plan** - Generate structured outline with H2 sections
|
||||
4. **Execute** - Auto-generate full article from plan
|
||||
5. **Revise** - Regenerate individual blocks or sections
|
||||
|
||||
### Key Features
|
||||
|
||||
- ✅ Single API key via OpenRouter
|
||||
- ✅ Built-in web search with toggle
|
||||
- ✅ Real-time cost tracking
|
||||
- ✅ Gutenberg block integration
|
||||
- ✅ Block-level regeneration
|
||||
- ✅ Free tier support (25+ free models)
|
||||
|
||||
## Installation
|
||||
|
||||
1. Download the plugin ZIP file
|
||||
2. Upload to WordPress plugins directory
|
||||
3. Activate the plugin
|
||||
4. Configure settings in **Settings > Agentic Writer**
|
||||
|
||||
## Configuration
|
||||
|
||||
### Get OpenRouter API Key
|
||||
|
||||
1. Visit [OpenRouter.ai](https://openrouter.ai/keys)
|
||||
2. Create an account (or use free tier)
|
||||
3. Generate an API key
|
||||
4. Paste in plugin settings
|
||||
|
||||
### Recommended Models
|
||||
|
||||
**Planning Model:**
|
||||
- `google/gemini-2.0-flash-exp` (Free, Fast) - Recommended
|
||||
- `xiaomi/mimo-v2-flash` (Free, High Quality)
|
||||
- `anthropic/claude-sonnet-4-20250514` (Paid, Excellent)
|
||||
|
||||
**Execution Model:**
|
||||
- `anthropic/claude-sonnet-4-20250514` (Recommended)
|
||||
- `anthropic/claude-opus-4-20250514` (Premium, Best Quality)
|
||||
- `meta-llama/llama-3.3-70b` (Free)
|
||||
- `qwen/qwen3-coder-480b` (Free, Technical Writing)
|
||||
|
||||
**Image Model:**
|
||||
- `black-forest-labs/flux-schnell` (Fast, $0.04/image)
|
||||
- `black-forest-labs/flux-pro` (Premium, $0.25/image)
|
||||
|
||||
### Web Search
|
||||
|
||||
Toggle web search in the Research phase:
|
||||
- **Cost:** ~$0.02 per search (Exa engine)
|
||||
- **Engine:** Auto, Native, or Exa
|
||||
- **Depth:** Low, Medium, or High
|
||||
|
||||
## Usage
|
||||
|
||||
1. Open WordPress editor for a new post
|
||||
2. Click "Agentic Writer" in the sidebar
|
||||
3. **Brainstorm:** Type your raw ideas or topic
|
||||
4. **Research:** (Optional) AI searches the web for current info
|
||||
5. **Plan:** Review and edit the generated outline
|
||||
6. **Execute:** Click to generate the full article
|
||||
7. **Revise:** Regenerate blocks as needed
|
||||
|
||||
## Cost Estimation
|
||||
|
||||
**Per Article (2,500 words):**
|
||||
- Planning: ~$0.0007 (with free model)
|
||||
- Research: ~$0.02 (if web search enabled)
|
||||
- Writing: ~$0.633 (with Claude Sonnet)
|
||||
- Image: ~$0.04 (with FLUX Schnell)
|
||||
- **Total:** ~$0.70
|
||||
|
||||
**Free Tier:**
|
||||
- Planning & Writing: $0.00 (with free models)
|
||||
- Research: $0.00 (skip web search)
|
||||
- **Total:** $0.00
|
||||
|
||||
## Requirements
|
||||
|
||||
- WordPress 6.6+
|
||||
- PHP 7.4+
|
||||
- Gutenberg Editor
|
||||
- OpenRouter API Key (or use free tier models)
|
||||
|
||||
## Security
|
||||
|
||||
- API keys are stored encrypted in WordPress options
|
||||
- All user inputs are sanitized
|
||||
- Nonces verified for all AJAX requests
|
||||
- No external data collection
|
||||
|
||||
## Support
|
||||
|
||||
- GitHub: [https://github.com/wp-agentic-writer/wp-agentic-writer](https://github.com/wp-agentic-writer/wp-agentic-writer)
|
||||
- Issues: [https://github.com/wp-agentic-writer/wp-agentic-writer/issues](https://github.com/wp-agentic-writer/wp-agentic-writer/issues)
|
||||
|
||||
## License
|
||||
|
||||
GPL-2.0+
|
||||
|
||||
## Credits
|
||||
|
||||
Developed with ❤️ for developers who struggle with blogging.
|
||||
|
||||
Uses [OpenRouter](https://openrouter.ai/) for unified AI model access.
|
||||
1139
docs/user-facing/WHAT_IS_WP_AGENTIC_WRITER.md
Normal file
1139
docs/user-facing/WHAT_IS_WP_AGENTIC_WRITER.md
Normal file
File diff suppressed because it is too large
Load Diff
1220
docs/user-facing/brave_search_integration.md
Normal file
1220
docs/user-facing/brave_search_integration.md
Normal file
File diff suppressed because it is too large
Load Diff
7
docs/user-facing/downloads/.gitignore
vendored
Normal file
7
docs/user-facing/downloads/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# Ignore node_modules in local backend package
|
||||
agentic-writer-local-backend/node_modules/
|
||||
agentic-writer-local-backend/proxy.log
|
||||
agentic-writer-local-backend/proxy.pid
|
||||
|
||||
# Keep the distributable ZIP
|
||||
!agentic-writer-local-backend.zip
|
||||
BIN
docs/user-facing/downloads/agentic-writer-local-backend.zip
Normal file
BIN
docs/user-facing/downloads/agentic-writer-local-backend.zip
Normal file
Binary file not shown.
@@ -0,0 +1,170 @@
|
||||
# Agentic Writer Local Backend
|
||||
|
||||
Run unlimited AI content generation on your own machine using your Claude CLI + Z.ai/Anthropic account.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before starting, ensure you have:
|
||||
|
||||
- ✅ **Claude CLI** installed and configured
|
||||
- Get it: [https://claude.ai/code](https://claude.ai/code) or [https://z.ai](https://z.ai)
|
||||
- Verify: `claude --version` or `which claude`
|
||||
- ✅ **Node.js 18+** installed
|
||||
- Download: [https://nodejs.org](https://nodejs.org)
|
||||
- Verify: `node --version`
|
||||
- ✅ **Z.ai Coding Plan** or **Anthropic API key** configured in Claude CLI
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Extract Package
|
||||
|
||||
```bash
|
||||
unzip agentic-writer-local-backend.zip
|
||||
cd agentic-writer-local-backend
|
||||
```
|
||||
|
||||
### 2. Start the Proxy
|
||||
|
||||
```bash
|
||||
chmod +x *.sh
|
||||
./start-proxy.sh
|
||||
```
|
||||
|
||||
You'll see:
|
||||
|
||||
```
|
||||
═══════════════════════════════════════════════════
|
||||
✅ Local Backend Running!
|
||||
═══════════════════════════════════════════════════
|
||||
|
||||
Your Configuration:
|
||||
Base URL: http://192.168.1.105:8080
|
||||
API Key: dummy
|
||||
Model: claude-local
|
||||
```
|
||||
|
||||
### 3. Configure WordPress Plugin
|
||||
|
||||
1. Open **WP Admin** → **Agentic Writer** → **Settings** → **Local Backend**
|
||||
2. Paste the **Base URL** shown above
|
||||
3. API Key: `dummy`
|
||||
4. Click **Test Connection** → should show ✅
|
||||
5. Start generating content!
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
./start-proxy.sh # Start proxy (runs in background)
|
||||
./stop-proxy.sh # Stop proxy
|
||||
./test-connection.sh # Test if proxy responds
|
||||
./get-local-ip.sh # Find your local IP address
|
||||
tail -f proxy.log # View real-time logs
|
||||
```
|
||||
|
||||
## Firewall Setup
|
||||
|
||||
The proxy needs to accept connections from your WordPress site.
|
||||
|
||||
### macOS
|
||||
|
||||
1. **System Settings** → **Network** → **Firewall**
|
||||
2. Click **Options** → **Add** → Select `node`
|
||||
3. Set to **Allow incoming connections**
|
||||
|
||||
### Linux (ufw)
|
||||
|
||||
```bash
|
||||
sudo ufw allow 8080/tcp
|
||||
sudo ufw reload
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
1. **Windows Defender Firewall** → **Advanced Settings**
|
||||
2. **Inbound Rules** → **New Rule**
|
||||
3. **Port** → TCP **8080** → **Allow**
|
||||
|
||||
## How It Works
|
||||
|
||||
```
|
||||
WordPress Plugin → HTTP POST → Local Proxy (port 8080)
|
||||
↓
|
||||
Spawns Claude CLI
|
||||
↓
|
||||
Returns AI Response
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- 🆓 **Free**: Uses your existing Z.ai/Anthropic subscription
|
||||
- 🔒 **Private**: Content never leaves your network
|
||||
- ⚡ **Fast**: LAN latency (~50-200ms)
|
||||
- 🚀 **Unlimited**: No rate limits, no token counting
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
See [TROUBLESHOOTING.md](TROUBLESHOOTING.md) for detailed solutions.
|
||||
|
||||
### Quick Fixes
|
||||
|
||||
**"Connection failed" in plugin:**
|
||||
```bash
|
||||
# Check proxy is running
|
||||
ps aux | grep claude-proxy
|
||||
|
||||
# Restart if needed
|
||||
./stop-proxy.sh && ./start-proxy.sh
|
||||
```
|
||||
|
||||
**"Claude CLI not found":**
|
||||
```bash
|
||||
# Verify Claude is installed
|
||||
which claude
|
||||
claude --version
|
||||
|
||||
# Test Claude works
|
||||
echo "Hello" | claude
|
||||
```
|
||||
|
||||
**"Wrong IP address":**
|
||||
```bash
|
||||
# Find your correct IP
|
||||
./get-local-ip.sh
|
||||
|
||||
# Or manually:
|
||||
# macOS: ipconfig getifaddr en0
|
||||
# Linux: ip route get 1 | awk '{print $7}'
|
||||
```
|
||||
|
||||
**Port 8080 already in use:**
|
||||
```bash
|
||||
# Find what's using it
|
||||
lsof -i :8080
|
||||
|
||||
# Change port (edit claude-proxy.js)
|
||||
PORT=9000 node claude-proxy.js
|
||||
# Update plugin Base URL to: http://your-ip:9000
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Proxy binds to `0.0.0.0` (all network interfaces) for LAN access
|
||||
- No authentication by design (LAN trust model)
|
||||
- All request prompts are logged to `proxy.log`
|
||||
- For internet exposure, use ngrok/reverse proxy with authentication
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```bash
|
||||
PORT=9000 ./start-proxy.sh # Use different port
|
||||
NODE_ENV=production # Production mode
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
- **Documentation**: [Plugin Docs](https://github.com/your/plugin)
|
||||
- **Issues**: [GitHub Issues](https://github.com/your/plugin/issues)
|
||||
- **Community**: [Discord](https://discord.gg/your-server)
|
||||
|
||||
## License
|
||||
|
||||
GPL-2.0+ - Same as WP Agentic Writer plugin
|
||||
@@ -0,0 +1,339 @@
|
||||
# Troubleshooting Guide
|
||||
|
||||
Common issues and solutions for Agentic Writer Local Backend.
|
||||
|
||||
## Connection Issues
|
||||
|
||||
### "Connection timeout" in Plugin
|
||||
|
||||
**Symptoms:**
|
||||
- Plugin shows "Connection timeout" error
|
||||
- Test connection fails
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Check proxy is running:**
|
||||
```bash
|
||||
ps aux | grep claude-proxy
|
||||
```
|
||||
|
||||
2. **Restart proxy:**
|
||||
```bash
|
||||
./stop-proxy.sh
|
||||
./start-proxy.sh
|
||||
```
|
||||
|
||||
3. **Check logs:**
|
||||
```bash
|
||||
tail -f proxy.log
|
||||
```
|
||||
|
||||
4. **Verify IP address:**
|
||||
```bash
|
||||
./get-local-ip.sh
|
||||
```
|
||||
|
||||
### "Connection refused"
|
||||
|
||||
**Cause:** Proxy not running or wrong IP
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Start proxy:**
|
||||
```bash
|
||||
./start-proxy.sh
|
||||
```
|
||||
|
||||
2. **Check firewall:**
|
||||
- macOS: System Settings → Network → Firewall → Allow Node.js
|
||||
- Linux: `sudo ufw allow 8080/tcp`
|
||||
- Windows: Defender Firewall → Allow port 8080
|
||||
|
||||
3. **Test locally first:**
|
||||
```bash
|
||||
curl http://localhost:8080/ping
|
||||
# Should return: pong
|
||||
```
|
||||
|
||||
## Claude CLI Issues
|
||||
|
||||
### "Claude CLI not found"
|
||||
|
||||
**Verify installation:**
|
||||
```bash
|
||||
which claude
|
||||
# macOS: /opt/homebrew/bin/claude or /usr/local/bin/claude
|
||||
# Linux: ~/.local/bin/claude or /usr/bin/claude
|
||||
```
|
||||
|
||||
**Fix PATH:**
|
||||
```bash
|
||||
# Add to ~/.zshrc or ~/.bashrc
|
||||
export PATH="/opt/homebrew/bin:$PATH"
|
||||
source ~/.zshrc
|
||||
```
|
||||
|
||||
**Reinstall Claude CLI:**
|
||||
- Visit: [https://claude.ai/code](https://claude.ai/code)
|
||||
- Follow installation instructions
|
||||
|
||||
### "No response from Claude"
|
||||
|
||||
**Test Claude manually:**
|
||||
```bash
|
||||
echo "Hello, reply with: Test successful" | claude
|
||||
```
|
||||
|
||||
**Check authentication:**
|
||||
```bash
|
||||
claude --version
|
||||
# Should show version and auth status
|
||||
```
|
||||
|
||||
**Reconfigure Claude:**
|
||||
- Check Z.ai account: [https://z.ai](https://z.ai)
|
||||
- Or Anthropic API key setup
|
||||
|
||||
## Network Issues
|
||||
|
||||
### Wrong IP Address Detected
|
||||
|
||||
**Find correct IP:**
|
||||
```bash
|
||||
# macOS
|
||||
ipconfig getifaddr en0 # WiFi
|
||||
ipconfig getifaddr en1 # Ethernet
|
||||
|
||||
# Linux
|
||||
ip route get 1 | awk '{print $7}'
|
||||
hostname -I
|
||||
|
||||
# Windows
|
||||
ipconfig
|
||||
# Look for "IPv4 Address" under active adapter
|
||||
```
|
||||
|
||||
**Update plugin settings:**
|
||||
- Use the correct IP in Base URL: `http://CORRECT-IP:8080`
|
||||
|
||||
### Port 8080 Already in Use
|
||||
|
||||
**Find what's using it:**
|
||||
```bash
|
||||
lsof -i :8080
|
||||
# or
|
||||
netstat -anp | grep 8080
|
||||
```
|
||||
|
||||
**Change port:**
|
||||
|
||||
1. Edit `claude-proxy.js`:
|
||||
```javascript
|
||||
const PORT = process.env.PORT || 9000; // Change 8080 to 9000
|
||||
```
|
||||
|
||||
2. Restart proxy:
|
||||
```bash
|
||||
./stop-proxy.sh
|
||||
PORT=9000 ./start-proxy.sh
|
||||
```
|
||||
|
||||
3. Update plugin Base URL: `http://your-ip:9000`
|
||||
|
||||
## Performance Issues
|
||||
|
||||
### Slow Response Times
|
||||
|
||||
**Normal latency:**
|
||||
- Local network: 50-200ms
|
||||
- Claude CLI processing: 2-30 seconds depending on prompt
|
||||
|
||||
**If consistently slow:**
|
||||
|
||||
1. **Check network:**
|
||||
```bash
|
||||
ping 192.168.1.105 # Your proxy IP
|
||||
```
|
||||
|
||||
2. **Monitor logs:**
|
||||
```bash
|
||||
tail -f proxy.log
|
||||
```
|
||||
|
||||
3. **Check machine resources:**
|
||||
- CPU usage: Claude CLI is CPU-intensive
|
||||
- Memory: Ensure sufficient RAM available
|
||||
|
||||
### Proxy Crashes
|
||||
|
||||
**Check logs:**
|
||||
```bash
|
||||
cat proxy.log | tail -50
|
||||
```
|
||||
|
||||
**Common causes:**
|
||||
- Out of memory: Close other applications
|
||||
- Claude CLI timeout: Increase timeout in `claude-proxy.js`
|
||||
- Malformed requests: Check plugin version compatibility
|
||||
|
||||
**Restart with clean state:**
|
||||
```bash
|
||||
./stop-proxy.sh
|
||||
rm proxy.log
|
||||
./start-proxy.sh
|
||||
```
|
||||
|
||||
## Plugin Integration Issues
|
||||
|
||||
### "Invalid response format"
|
||||
|
||||
**Cause:** Claude response doesn't match expected JSON format
|
||||
|
||||
**Debug:**
|
||||
1. Check `proxy.log` for actual Claude output
|
||||
2. Test manually:
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/v1/messages \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"messages":[{"role":"user","content":"Hello"}]}'
|
||||
```
|
||||
|
||||
3. Update Claude CLI if outdated:
|
||||
```bash
|
||||
claude --version
|
||||
# Upgrade if needed
|
||||
```
|
||||
|
||||
### Cost Tracking Shows $0
|
||||
|
||||
**Expected behavior:** Local backend is free, plugin should show `$0.00 (Local)`
|
||||
|
||||
**If concerned:**
|
||||
- This is correct - local backend has no API costs
|
||||
- Dashboard should show "X requests local (free)"
|
||||
|
||||
## Advanced Troubleshooting
|
||||
|
||||
### Enable Debug Logging
|
||||
|
||||
Edit `claude-proxy.js`:
|
||||
```javascript
|
||||
const DEBUG = true; // Add at top of file
|
||||
|
||||
// In /v1/messages handler:
|
||||
if (DEBUG) {
|
||||
console.log('Full request:', JSON.stringify(req.body, null, 2));
|
||||
console.log('Full response:', output);
|
||||
}
|
||||
```
|
||||
|
||||
### Test with curl
|
||||
|
||||
**Ping:**
|
||||
```bash
|
||||
curl http://localhost:8080/ping
|
||||
# Expected: pong
|
||||
```
|
||||
|
||||
**Inference:**
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/v1/messages \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"messages": [
|
||||
{"role": "user", "content": "Reply with: Test successful"}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
**Expected response:**
|
||||
```json
|
||||
{
|
||||
"id": "local-1234567890",
|
||||
"object": "chat.completion",
|
||||
"model": "claude-local",
|
||||
"choices": [{
|
||||
"message": {
|
||||
"content": "Test successful"
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### Permissions Issues (macOS)
|
||||
|
||||
**Make scripts executable:**
|
||||
```bash
|
||||
chmod +x start-proxy.sh stop-proxy.sh test-connection.sh get-local-ip.sh
|
||||
```
|
||||
|
||||
**If "permission denied":**
|
||||
```bash
|
||||
# Check file permissions
|
||||
ls -la *.sh
|
||||
|
||||
# Reset if needed
|
||||
chmod 755 *.sh
|
||||
```
|
||||
|
||||
## Still Having Issues?
|
||||
|
||||
1. **Check system requirements:**
|
||||
- Node.js 18+: `node --version`
|
||||
- Claude CLI installed: `which claude`
|
||||
- Sufficient disk space: `df -h`
|
||||
|
||||
2. **Collect diagnostic info:**
|
||||
```bash
|
||||
echo "Node version:" $(node --version)
|
||||
echo "Claude path:" $(which claude)
|
||||
echo "Local IP:" $(./get-local-ip.sh)
|
||||
echo "Proxy status:" $(ps aux | grep claude-proxy)
|
||||
tail -20 proxy.log
|
||||
```
|
||||
|
||||
3. **Reset everything:**
|
||||
```bash
|
||||
./stop-proxy.sh
|
||||
rm -rf node_modules proxy.log proxy.pid
|
||||
npm install
|
||||
./start-proxy.sh
|
||||
```
|
||||
|
||||
4. **Get help:**
|
||||
- GitHub Issues: [Report Bug](https://github.com/your/plugin/issues)
|
||||
- Discord Community: [Join Chat](https://discord.gg/your-server)
|
||||
- Include: OS, Node version, Claude CLI version, error logs
|
||||
|
||||
## Environment-Specific Notes
|
||||
|
||||
### macOS
|
||||
|
||||
- Default Claude path: `/opt/homebrew/bin/claude`
|
||||
- Firewall: System Settings → Network → Firewall
|
||||
- IP detection: `ipconfig getifaddr en0`
|
||||
|
||||
### Linux
|
||||
|
||||
- Default Claude path: `~/.local/bin/claude`
|
||||
- Firewall: `sudo ufw allow 8080/tcp`
|
||||
- IP detection: `ip route get 1 | awk '{print $7}'`
|
||||
|
||||
### Windows
|
||||
|
||||
- Claude path varies, check `where claude`
|
||||
- Firewall: Windows Defender → Allow port 8080
|
||||
- IP detection: `ipconfig` (look for IPv4)
|
||||
- Scripts: Use Git Bash or WSL to run `.sh` scripts
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **LAN only:** Don't expose proxy to internet without authentication
|
||||
2. **Firewall:** Restrict to specific IPs if on shared network
|
||||
3. **Logs:** `proxy.log` contains all prompts - review periodically
|
||||
4. **Updates:** Keep Node.js and Claude CLI updated
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** 2025-02-27
|
||||
**Version:** 1.0.0
|
||||
@@ -0,0 +1,122 @@
|
||||
const express = require('express');
|
||||
const { spawn } = require('child_process');
|
||||
const app = express();
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
// Health check endpoint
|
||||
app.get('/ping', (req, res) => {
|
||||
res.send('pong');
|
||||
});
|
||||
|
||||
// Main inference endpoint (OpenAI-compatible format)
|
||||
app.post('/v1/messages', async (req, res) => {
|
||||
const { messages } = req.body;
|
||||
|
||||
if (!messages || !Array.isArray(messages) || messages.length === 0) {
|
||||
return res.status(400).json({
|
||||
error: {
|
||||
message: 'Invalid request: messages array required'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Extract the last user message as the prompt
|
||||
const lastMessage = messages[messages.length - 1];
|
||||
const prompt = lastMessage.content;
|
||||
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
console.log('Request from:', req.ip);
|
||||
console.log('Prompt length:', prompt.length, 'chars');
|
||||
console.log('Prompt preview:', prompt.substring(0, 150) + '...');
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
|
||||
// Spawn Claude CLI process
|
||||
const claude = spawn('claude', [], {
|
||||
stdio: ['pipe', 'pipe', 'pipe']
|
||||
});
|
||||
|
||||
let output = '';
|
||||
let errorOutput = '';
|
||||
|
||||
claude.stdout.on('data', (data) => {
|
||||
output += data.toString();
|
||||
process.stdout.write('.');
|
||||
});
|
||||
|
||||
claude.stderr.on('data', (data) => {
|
||||
errorOutput += data.toString();
|
||||
console.error('Claude stderr:', data.toString());
|
||||
});
|
||||
|
||||
claude.on('close', (code) => {
|
||||
console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
console.log('Claude exit code:', code);
|
||||
console.log('Response length:', output.length, 'chars');
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
|
||||
|
||||
if (code !== 0 || !output.trim()) {
|
||||
return res.status(500).json({
|
||||
error: {
|
||||
message: 'Claude CLI error',
|
||||
details: errorOutput || 'No response from Claude'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Return OpenAI-compatible response format
|
||||
res.json({
|
||||
id: 'local-' + Date.now(),
|
||||
object: 'chat.completion',
|
||||
created: Math.floor(Date.now() / 1000),
|
||||
model: 'claude-local',
|
||||
choices: [{
|
||||
index: 0,
|
||||
message: {
|
||||
role: 'assistant',
|
||||
content: output.trim()
|
||||
},
|
||||
finish_reason: 'stop'
|
||||
}],
|
||||
usage: {
|
||||
prompt_tokens: 0,
|
||||
completion_tokens: 0,
|
||||
total_tokens: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
claude.on('error', (err) => {
|
||||
console.error('Failed to spawn Claude CLI:', err);
|
||||
res.status(500).json({
|
||||
error: {
|
||||
message: 'Failed to spawn Claude CLI',
|
||||
details: err.message
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Send prompt to Claude after brief pause
|
||||
setTimeout(() => {
|
||||
claude.stdin.write(prompt + '\n');
|
||||
claude.stdin.end();
|
||||
}, 100);
|
||||
});
|
||||
|
||||
const PORT = process.env.PORT || 8080;
|
||||
app.listen(PORT, '0.0.0.0', () => {
|
||||
console.log('═══════════════════════════════════════════════════');
|
||||
console.log('🚀 Agentic Writer Local Backend Started!');
|
||||
console.log('═══════════════════════════════════════════════════');
|
||||
console.log(`Local: http://localhost:${PORT}`);
|
||||
console.log(`Network: http://YOUR-IP:${PORT}`);
|
||||
console.log('');
|
||||
console.log('Plugin Configuration:');
|
||||
console.log(` Base URL: http://YOUR-IP:${PORT}`);
|
||||
console.log(` API Key: dummy`);
|
||||
console.log(` Model: claude-local`);
|
||||
console.log('');
|
||||
console.log('Health check: GET /ping');
|
||||
console.log('Inference: POST /v1/messages');
|
||||
console.log('═══════════════════════════════════════════════════');
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Detecting your local IP address..."
|
||||
echo ""
|
||||
|
||||
# Detect local IP based on OS
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
# macOS - try en0 (WiFi) then en1 (Ethernet)
|
||||
IP=$(ipconfig getifaddr en0 2>/dev/null || ipconfig getifaddr en1 2>/dev/null || echo "")
|
||||
INTERFACE=$(ifconfig en0 &>/dev/null && echo "en0 (WiFi)" || echo "en1 (Ethernet)")
|
||||
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
# Linux
|
||||
IP=$(ip route get 1 | awk '{print $7;exit}' 2>/dev/null || hostname -I | awk '{print $1}')
|
||||
INTERFACE="default"
|
||||
else
|
||||
# Windows or unknown
|
||||
IP=$(hostname -I 2>/dev/null | awk '{print $1}' || echo "")
|
||||
INTERFACE="unknown"
|
||||
fi
|
||||
|
||||
if [ -z "$IP" ]; then
|
||||
echo "❌ Could not detect IP address automatically"
|
||||
echo ""
|
||||
echo "Manual detection:"
|
||||
echo " macOS: ipconfig getifaddr en0"
|
||||
echo " Linux: ip route get 1 | awk '{print \$7}'"
|
||||
echo " Windows: ipconfig (look for IPv4 Address)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Your local IP: $IP ($INTERFACE)"
|
||||
echo ""
|
||||
echo "Use this in your plugin settings:"
|
||||
echo " Base URL: http://$IP:8080"
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "agentic-writer-local-backend",
|
||||
"version": "1.0.0",
|
||||
"description": "Local backend proxy for WP Agentic Writer using Claude CLI",
|
||||
"main": "claude-proxy.js",
|
||||
"scripts": {
|
||||
"start": "node claude-proxy.js",
|
||||
"test": "curl http://localhost:8080/ping"
|
||||
},
|
||||
"keywords": [
|
||||
"wordpress",
|
||||
"ai",
|
||||
"claude",
|
||||
"proxy"
|
||||
],
|
||||
"author": "WP Agentic Writer",
|
||||
"license": "GPL-2.0+",
|
||||
"dependencies": {
|
||||
"express": "^4.18.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "🚀 Starting Agentic Writer Local Backend..."
|
||||
echo ""
|
||||
|
||||
# Check dependencies
|
||||
if ! command -v node &> /dev/null; then
|
||||
echo "❌ Node.js not found. Install from https://nodejs.org/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v claude &> /dev/null; then
|
||||
echo "❌ Claude CLI not found. Install and configure first."
|
||||
echo " Check: https://claude.ai/code or https://z.ai"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Auto-install express if needed
|
||||
if [ ! -d "node_modules" ]; then
|
||||
echo "📦 Installing dependencies..."
|
||||
npm install
|
||||
fi
|
||||
|
||||
# Detect local IP
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
# macOS
|
||||
LOCAL_IP=$(ipconfig getifaddr en0 2>/dev/null || ipconfig getifaddr en1 2>/dev/null || echo "127.0.0.1")
|
||||
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
# Linux
|
||||
LOCAL_IP=$(ip route get 1 | awk '{print $7;exit}' 2>/dev/null || echo "127.0.0.1")
|
||||
else
|
||||
# Windows/other
|
||||
LOCAL_IP="127.0.0.1"
|
||||
fi
|
||||
|
||||
echo "✅ Dependencies OK"
|
||||
echo "✅ Claude CLI found: $(which claude)"
|
||||
echo ""
|
||||
echo "Starting proxy server..."
|
||||
echo ""
|
||||
|
||||
# Start server in background
|
||||
nohup node claude-proxy.js > proxy.log 2>&1 &
|
||||
PID=$!
|
||||
echo $PID > proxy.pid
|
||||
|
||||
# Wait for server to boot
|
||||
sleep 2
|
||||
|
||||
# Test if running
|
||||
if kill -0 $PID 2>/dev/null; then
|
||||
echo "═══════════════════════════════════════════════════"
|
||||
echo "✅ Local Backend Running!"
|
||||
echo "═══════════════════════════════════════════════════"
|
||||
echo ""
|
||||
echo "Your Configuration:"
|
||||
echo " Base URL: http://$LOCAL_IP:8080"
|
||||
echo " API Key: dummy"
|
||||
echo " Model: claude-local"
|
||||
echo ""
|
||||
echo "Next Steps:"
|
||||
echo " 1. Open your WordPress Admin"
|
||||
echo " 2. Go to Agentic Writer → Settings → Local Backend"
|
||||
echo " 3. Paste the Base URL above"
|
||||
echo " 4. Click 'Test Connection'"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " Logs: tail -f proxy.log"
|
||||
echo " Stop: ./stop-proxy.sh"
|
||||
echo " Test: ./test-connection.sh"
|
||||
echo "═══════════════════════════════════════════════════"
|
||||
else
|
||||
echo "❌ Failed to start. Check proxy.log for errors."
|
||||
cat proxy.log
|
||||
rm -f proxy.pid
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -f proxy.pid ]; then
|
||||
PID=$(cat proxy.pid)
|
||||
if kill -0 $PID 2>/dev/null; then
|
||||
kill $PID
|
||||
rm proxy.pid
|
||||
echo "🛑 Local Backend stopped (PID: $PID)"
|
||||
else
|
||||
echo "⚠️ No process found with PID: $PID"
|
||||
rm proxy.pid
|
||||
fi
|
||||
else
|
||||
# Fallback: kill by process name
|
||||
pkill -f claude-proxy.js
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "🛑 Stopped all claude-proxy processes"
|
||||
else
|
||||
echo "ℹ️ No claude-proxy processes running"
|
||||
fi
|
||||
fi
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Testing local backend connection..."
|
||||
echo ""
|
||||
|
||||
# Test /ping endpoint
|
||||
echo "1. Testing health check..."
|
||||
PING_RESPONSE=$(curl -s http://localhost:8080/ping 2>&1)
|
||||
|
||||
if [ "$PING_RESPONSE" = "pong" ]; then
|
||||
echo " ✅ Health check passed"
|
||||
else
|
||||
echo " ❌ Health check failed"
|
||||
echo " Response: $PING_RESPONSE"
|
||||
echo ""
|
||||
echo "Is the proxy running? Check: ps aux | grep claude-proxy"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test /v1/messages endpoint
|
||||
echo "2. Testing inference..."
|
||||
RESPONSE=$(curl -s -X POST http://localhost:8080/v1/messages \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"messages":[{"role":"user","content":"Reply with exactly: Test successful"}]}' 2>&1)
|
||||
|
||||
echo " Response: $RESPONSE"
|
||||
|
||||
if echo "$RESPONSE" | grep -q "choices"; then
|
||||
echo " ✅ Inference endpoint working"
|
||||
echo ""
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "✅ Local Backend is working correctly!"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
else
|
||||
echo " ❌ Inference test failed"
|
||||
echo ""
|
||||
echo "Troubleshooting:"
|
||||
echo " 1. Check Claude CLI: echo 'test' | claude"
|
||||
echo " 2. Check logs: tail -f proxy.log"
|
||||
echo " 3. Restart proxy: ./stop-proxy.sh && ./start-proxy.sh"
|
||||
exit 1
|
||||
fi
|
||||
883
docs/user-facing/local-backend-feature.md
Normal file
883
docs/user-facing/local-backend-feature.md
Normal file
@@ -0,0 +1,883 @@
|
||||
# WP Agentic Writer - Local Backend Mode Feature Brief
|
||||
|
||||
## Overview
|
||||
|
||||
**Feature Name**: Local Backend Mode (Self-Hosted AI Proxy)
|
||||
|
||||
**Purpose**: Allow users to connect their WP Agentic Writer plugin to their own local Claude CLI (with Z.ai, OpenRouter, or official Anthropic) running on their development machine, enabling unlimited private AI content generation without external API costs or rate limits.
|
||||
|
||||
**Target Users**:
|
||||
- Developers with Claude CLI + Z.ai/Anthropic accounts
|
||||
- Users with coding plans (Z.ai, OpenRouter BYOK)
|
||||
- Privacy-conscious users wanting on-premise inference
|
||||
- High-volume content creators avoiding API metering
|
||||
|
||||
---
|
||||
|
||||
## User Journey
|
||||
|
||||
### Current State (Remote APIs)
|
||||
```
|
||||
User → WP Admin → Agentic Writer → OpenRouter/Z.ai Cloud → $$ per token
|
||||
```
|
||||
|
||||
### New State (Local Backend)
|
||||
```
|
||||
User's M1/PC: Claude CLI + Z.ai → Local Proxy (Port 8080)
|
||||
↓
|
||||
User → WP Admin (Live Site) → Agentic Writer → http://user-ip:8080 → FREE
|
||||
```
|
||||
|
||||
### Complete Flow
|
||||
1. User downloads "Agentic Writer Local Backend" package (ZIP)
|
||||
2. Extracts on machine with Claude CLI already installed
|
||||
3. Runs `./start-proxy.sh` → sees their local IP + config instructions
|
||||
4. Opens WP Admin → Agentic Writer Settings → "Local Backend" tab
|
||||
5. Enters: Base URL `http://192.168.1.105:8080`, API Key `dummy`
|
||||
6. Clicks "Test Connection" → sees success message
|
||||
7. Generates articles → content flows through their private backend → zero API costs
|
||||
|
||||
---
|
||||
|
||||
## Technical Architecture
|
||||
|
||||
### Components
|
||||
|
||||
#### 1. Local Proxy Package (Distributed ZIP)
|
||||
**File**: `agentic-writer-local-backend.zip`
|
||||
|
||||
**Contents**:
|
||||
```
|
||||
agentic-writer-local-backend/
|
||||
├── claude-proxy.js # Node.js HTTP server (10 lines)
|
||||
├── start-proxy.sh # Launch script with IP detection
|
||||
├── stop-proxy.sh # Clean shutdown
|
||||
├── test-connection.sh # Verify proxy responds
|
||||
├── get-local-ip.sh # Helper to find machine IP
|
||||
├── package.json # Express dependency
|
||||
├── README.md # User setup guide
|
||||
├── TROUBLESHOOTING.md # Common issues + fixes
|
||||
└── examples/
|
||||
└── plugin-config-screenshot.png
|
||||
```
|
||||
|
||||
#### 2. Core Proxy Server (`claude-proxy.js`)
|
||||
**Technology**: Node.js + Express
|
||||
**Port**: 8080 (configurable)
|
||||
**Dependencies**: `express` only
|
||||
|
||||
**Code**:
|
||||
```javascript
|
||||
const express = require('express');
|
||||
const { spawn } = require('child_process');
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
// Health check endpoint
|
||||
app.get('/ping', (req, res) => res.send('pong'));
|
||||
|
||||
// Main inference endpoint
|
||||
app.post('/v1/messages', async (req, res) => {
|
||||
const { messages } = req.body;
|
||||
const prompt = messages[messages.length - 1].content;
|
||||
|
||||
console.log('Request from:', req.ip);
|
||||
console.log('Prompt:', prompt.substring(0, 100) + '...');
|
||||
|
||||
const claude = spawn('claude', []);
|
||||
let output = '';
|
||||
|
||||
claude.stdout.on('data', (data) => {
|
||||
output += data.toString();
|
||||
console.log('Claude response chunk:', data.toString().length, 'bytes');
|
||||
});
|
||||
|
||||
claude.stderr.on('data', (data) => {
|
||||
console.error('Claude stderr:', data.toString());
|
||||
});
|
||||
|
||||
claude.on('close', (code) => {
|
||||
console.log('Claude exit code:', code);
|
||||
res.json({
|
||||
id: 'local-' + Date.now(),
|
||||
object: 'chat.completion',
|
||||
created: Math.floor(Date.now() / 1000),
|
||||
model: 'claude-local',
|
||||
choices: [{
|
||||
index: 0,
|
||||
message: {
|
||||
role: 'assistant',
|
||||
content: output.trim() || 'No response from Claude'
|
||||
},
|
||||
finish_reason: 'stop'
|
||||
}]
|
||||
});
|
||||
});
|
||||
|
||||
// Send prompt after brief pause (let Claude boot)
|
||||
setTimeout(() => {
|
||||
claude.stdin.write(prompt + '\n');
|
||||
claude.stdin.end();
|
||||
}, 500);
|
||||
});
|
||||
|
||||
const PORT = process.env.PORT || 8080;
|
||||
app.listen(PORT, '0.0.0.0', () => {
|
||||
console.log('═══════════════════════════════════════════════════');
|
||||
console.log('🚀 Agentic Writer Local Backend Started!');
|
||||
console.log('═══════════════════════════════════════════════════');
|
||||
console.log(`Local: http://localhost:${PORT}`);
|
||||
console.log(`Network: http://YOUR-IP:${PORT}`);
|
||||
console.log('');
|
||||
console.log('Plugin Configuration:');
|
||||
console.log(` Base URL: http://YOUR-IP:${PORT}`);
|
||||
console.log(` API Key: dummy`);
|
||||
console.log(` Model: glm-4-7 (or your Claude model)`);
|
||||
console.log('═══════════════════════════════════════════════════');
|
||||
});
|
||||
```
|
||||
|
||||
**Key Features**:
|
||||
- Spawns user's local `claude` CLI for each request
|
||||
- Captures stdout/stderr for debugging
|
||||
- OpenAI-compatible `/v1/messages` endpoint
|
||||
- Health check `/ping` for connection testing
|
||||
- Logs all requests for transparency
|
||||
|
||||
#### 3. Startup Script (`start-proxy.sh`)
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
echo "🚀 Starting Agentic Writer Local Backend..."
|
||||
echo ""
|
||||
|
||||
# Check dependencies
|
||||
if ! command -v node &> /dev/null; then
|
||||
echo "❌ Node.js not found. Install from https://nodejs.org/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v claude &> /dev/null; then
|
||||
echo "❌ Claude CLI not found. Install and configure first."
|
||||
echo " Check: https://claude.ai/code or https://z.ai"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Auto-install express if needed
|
||||
if [ ! -d "node_modules" ]; then
|
||||
echo "📦 Installing dependencies..."
|
||||
npm install express
|
||||
fi
|
||||
|
||||
# Detect local IP
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
# macOS
|
||||
LOCAL_IP=$(ifconfig en0 | grep "inet " | awk '{print $2}')
|
||||
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
|
||||
# Linux
|
||||
LOCAL_IP=$(ip route get 1 | awk '{print $7;exit}')
|
||||
else
|
||||
# Windows/other
|
||||
LOCAL_IP="YOUR-IP"
|
||||
fi
|
||||
|
||||
echo "✅ Dependencies OK"
|
||||
echo "✅ Claude CLI found"
|
||||
echo ""
|
||||
echo "Starting proxy server..."
|
||||
echo ""
|
||||
|
||||
# Start server in background
|
||||
nohup node claude-proxy.js > proxy.log 2>&1 &
|
||||
PID=$!
|
||||
echo $PID > proxy.pid
|
||||
|
||||
# Wait for server to boot
|
||||
sleep 2
|
||||
|
||||
# Test if running
|
||||
if kill -0 $PID 2>/dev/null; then
|
||||
echo "═══════════════════════════════════════════════════"
|
||||
echo "✅ Local Backend Running!"
|
||||
echo "═══════════════════════════════════════════════════"
|
||||
echo ""
|
||||
echo "Your Configuration:"
|
||||
echo " Base URL: http://$LOCAL_IP:8080"
|
||||
echo " API Key: dummy"
|
||||
echo " Model: glm-4-7"
|
||||
echo ""
|
||||
echo "Next Steps:"
|
||||
echo " 1. Open your WordPress Admin"
|
||||
echo " 2. Go to Agentic Writer → Settings → Local Backend"
|
||||
echo " 3. Paste the Base URL above"
|
||||
echo " 4. Click 'Test Connection'"
|
||||
echo ""
|
||||
echo "Logs: tail -f proxy.log"
|
||||
echo "Stop: ./stop-proxy.sh"
|
||||
echo "═══════════════════════════════════════════════════"
|
||||
else
|
||||
echo "❌ Failed to start. Check proxy.log for errors."
|
||||
cat proxy.log
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
#### 4. Stop Script (`stop-proxy.sh`)
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
if [ -f proxy.pid ]; then
|
||||
PID=$(cat proxy.pid)
|
||||
if kill -0 $PID 2>/dev/null; then
|
||||
kill $PID
|
||||
rm proxy.pid
|
||||
echo "🛑 Local Backend stopped (PID: $PID)"
|
||||
else
|
||||
echo "⚠️ No process found with PID: $PID"
|
||||
rm proxy.pid
|
||||
fi
|
||||
else
|
||||
# Fallback: kill by process name
|
||||
pkill -f claude-proxy.js
|
||||
echo "🛑 Stopped all claude-proxy processes"
|
||||
fi
|
||||
```
|
||||
|
||||
#### 5. Connection Test Script (`test-connection.sh`)
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
echo "Testing local backend connection..."
|
||||
|
||||
RESPONSE=$(curl -s -X POST http://localhost:8080/v1/messages \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"messages":[{"role":"user","content":"Reply with: Test successful"}]}')
|
||||
|
||||
if echo "$RESPONSE" | grep -q "Test successful"; then
|
||||
echo "✅ Local Backend working correctly!"
|
||||
echo "Response: $RESPONSE"
|
||||
else
|
||||
echo "❌ Test failed. Response:"
|
||||
echo "$RESPONSE"
|
||||
echo ""
|
||||
echo "Troubleshooting:"
|
||||
echo " 1. Check proxy is running: ps aux | grep claude-proxy"
|
||||
echo " 2. Check logs: tail -f proxy.log"
|
||||
echo " 3. Verify Claude CLI: claude --version"
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Plugin Integration (WordPress Side)
|
||||
|
||||
### 1. Settings Page - New "Local Backend" Tab
|
||||
|
||||
**Location**: WP Admin → Agentic Writer → Settings → Local Backend
|
||||
|
||||
**UI Elements**:
|
||||
|
||||
```php
|
||||
// Add to plugin settings page
|
||||
function render_local_backend_settings() {
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h2><?php _e('Local Backend Mode', 'wp-agentic-writer'); ?></h2>
|
||||
|
||||
<!-- Download Section -->
|
||||
<div class="notice notice-info inline">
|
||||
<h3>📦 Step 1: Download Local Backend Package</h3>
|
||||
<p>Run AI inference on your own machine with your Claude CLI + Z.ai account.</p>
|
||||
<p>
|
||||
<a href="<?php echo plugins_url('downloads/agentic-writer-local-backend.zip', __FILE__); ?>"
|
||||
class="button button-primary" download>
|
||||
Download Local Backend (v1.0.0)
|
||||
</a>
|
||||
</p>
|
||||
<details>
|
||||
<summary>Prerequisites</summary>
|
||||
<ul>
|
||||
<li>✅ Claude CLI installed (<a href="https://claude.ai/code" target="_blank">Get Claude Code</a> or <a href="https://z.ai" target="_blank">Z.ai</a>)</li>
|
||||
<li>✅ Node.js 18+ (<a href="https://nodejs.org" target="_blank">Download</a>)</li>
|
||||
<li>✅ Z.ai Coding Plan or Anthropic API key configured in Claude CLI</li>
|
||||
</ul>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<!-- Configuration Section -->
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="local_backend_url"><?php _e('Base URL', 'wp-agentic-writer'); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="url"
|
||||
id="local_backend_url"
|
||||
name="agentic_writer_settings[local_backend_url]"
|
||||
value="<?php echo esc_attr(get_option('agentic_writer_local_backend_url', '')); ?>"
|
||||
class="regular-text"
|
||||
placeholder="http://192.168.1.105:8080">
|
||||
<p class="description">
|
||||
Enter the URL from your Local Backend startup message (e.g., http://YOUR-IP:8080)
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="local_backend_key"><?php _e('API Key', 'wp-agentic-writer'); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="text"
|
||||
id="local_backend_key"
|
||||
name="agentic_writer_settings[local_backend_key]"
|
||||
value="<?php echo esc_attr(get_option('agentic_writer_local_backend_key', 'dummy')); ?>"
|
||||
class="regular-text"
|
||||
placeholder="dummy">
|
||||
<p class="description">
|
||||
Use "dummy" for local backend (ignored by proxy)
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="local_backend_model"><?php _e('Model', 'wp-agentic-writer'); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="text"
|
||||
id="local_backend_model"
|
||||
name="agentic_writer_settings[local_backend_model]"
|
||||
value="<?php echo esc_attr(get_option('agentic_writer_local_backend_model', 'glm-4-7')); ?>"
|
||||
class="regular-text"
|
||||
placeholder="glm-4-7">
|
||||
<p class="description">
|
||||
Model identifier (informational only, proxy uses your Claude CLI default)
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- Connection Test -->
|
||||
<p>
|
||||
<button type="button" id="test-local-backend" class="button">
|
||||
🔌 Test Connection
|
||||
</button>
|
||||
<span id="connection-status" style="margin-left: 10px;"></span>
|
||||
</p>
|
||||
|
||||
<!-- Help Section -->
|
||||
<div class="notice notice-warning inline" style="margin-top: 20px;">
|
||||
<h4>🛠️ Troubleshooting</h4>
|
||||
<ul>
|
||||
<li><strong>Connection failed?</strong> Ensure proxy is running: <code>./start-proxy.sh</code></li>
|
||||
<li><strong>Wrong IP?</strong> Run <code>./get-local-ip.sh</code> to find correct address</li>
|
||||
<li><strong>Firewall blocking?</strong> Allow Node.js on port 8080 (System Preferences → Network → Firewall)</li>
|
||||
<li><strong>Claude not found?</strong> Check Claude CLI: <code>which claude</code> or <code>claude --version</code></li>
|
||||
</ul>
|
||||
<p><a href="https://docs.your-site.com/local-backend" target="_blank">Full Setup Guide →</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
jQuery('#test-local-backend').on('click', function() {
|
||||
const btn = jQuery(this);
|
||||
const status = jQuery('#connection-status');
|
||||
const url = jQuery('#local_backend_url').val();
|
||||
|
||||
if (!url) {
|
||||
status.html('⚠️ Enter Base URL first');
|
||||
return;
|
||||
}
|
||||
|
||||
btn.prop('disabled', true).text('Testing...');
|
||||
status.html('⏳ Connecting...');
|
||||
|
||||
jQuery.ajax({
|
||||
url: ajaxurl,
|
||||
method: 'POST',
|
||||
data: {
|
||||
action: 'test_local_backend',
|
||||
url: url,
|
||||
nonce: '<?php echo wp_create_nonce('test_local_backend'); ?>'
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
status.html('✅ Connected! Ready to generate content.');
|
||||
status.css('color', 'green');
|
||||
} else {
|
||||
status.html('❌ Failed: ' + response.data.message);
|
||||
status.css('color', 'red');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
status.html('❌ Connection failed. Check URL and proxy status.');
|
||||
status.css('color', 'red');
|
||||
},
|
||||
complete: function() {
|
||||
btn.prop('disabled', false).text('🔌 Test Connection');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
```
|
||||
|
||||
### 2. AJAX Connection Test Handler
|
||||
|
||||
```php
|
||||
// Add to plugin main file
|
||||
add_action('wp_ajax_test_local_backend', 'test_local_backend_connection');
|
||||
|
||||
function test_local_backend_connection() {
|
||||
check_ajax_referer('test_local_backend', 'nonce');
|
||||
|
||||
$url = sanitize_url($_POST['url']);
|
||||
|
||||
// Test /ping endpoint
|
||||
$response = wp_remote_get($url . '/ping', [
|
||||
'timeout' => 5,
|
||||
'sslverify' => false // Local network
|
||||
]);
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
wp_send_json_error([
|
||||
'message' => 'Cannot reach proxy: ' . $response->get_error_message()
|
||||
]);
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
|
||||
if ($body === 'pong') {
|
||||
// Test actual inference
|
||||
$test_response = wp_remote_post($url . '/v1/messages', [
|
||||
'headers' => ['Content-Type' => 'application/json'],
|
||||
'body' => json_encode([
|
||||
'messages' => [
|
||||
['role' => 'user', 'content' => 'Reply with: Connection test successful']
|
||||
]
|
||||
]),
|
||||
'timeout' => 30
|
||||
]);
|
||||
|
||||
if (!is_wp_error($test_response)) {
|
||||
$result = json_decode(wp_remote_retrieve_body($test_response), true);
|
||||
if (isset($result['choices'][0]['message']['content'])) {
|
||||
wp_send_json_success([
|
||||
'message' => 'Proxy responding correctly',
|
||||
'sample' => $result['choices'][0]['message']['content']
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wp_send_json_error(['message' => 'Proxy not responding correctly']);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Provider Integration
|
||||
|
||||
**Add to existing provider system**:
|
||||
|
||||
```php
|
||||
// In your provider factory/registry
|
||||
class LocalBackendProvider extends BaseProvider {
|
||||
|
||||
public function generate_content($prompt, $options = []) {
|
||||
$url = get_option('agentic_writer_local_backend_url');
|
||||
$api_key = get_option('agentic_writer_local_backend_key', 'dummy');
|
||||
|
||||
if (empty($url)) {
|
||||
return new WP_Error('no_url', 'Local Backend URL not configured');
|
||||
}
|
||||
|
||||
$response = wp_remote_post($url . '/v1/messages', [
|
||||
'headers' => [
|
||||
'Content-Type' => 'application/json',
|
||||
'Authorization' => 'Bearer ' . $api_key
|
||||
],
|
||||
'body' => json_encode([
|
||||
'model' => get_option('agentic_writer_local_backend_model', 'glm-4-7'),
|
||||
'messages' => [
|
||||
['role' => 'user', 'content' => $prompt]
|
||||
]
|
||||
]),
|
||||
'timeout' => 120 // Long timeout for content generation
|
||||
]);
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$body = json_decode(wp_remote_retrieve_body($response), true);
|
||||
|
||||
if (isset($body['choices'][0]['message']['content'])) {
|
||||
return $body['choices'][0]['message']['content'];
|
||||
}
|
||||
|
||||
return new WP_Error('invalid_response', 'Invalid response from local backend');
|
||||
}
|
||||
|
||||
public function is_configured() {
|
||||
return !empty(get_option('agentic_writer_local_backend_url'));
|
||||
}
|
||||
}
|
||||
|
||||
// Register provider
|
||||
add_filter('agentic_writer_providers', function($providers) {
|
||||
$providers['local_backend'] = [
|
||||
'name' => 'Local Backend (Your Machine)',
|
||||
'class' => 'LocalBackendProvider',
|
||||
'icon' => '🖥️',
|
||||
'description' => 'Use your own Claude CLI + Z.ai for unlimited private generation'
|
||||
];
|
||||
return $providers;
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## User Documentation
|
||||
|
||||
### README.md (Included in ZIP)
|
||||
|
||||
```markdown
|
||||
# Agentic Writer Local Backend
|
||||
|
||||
Run unlimited AI content generation on your own machine using your Claude CLI.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- ✅ Claude CLI installed and configured
|
||||
- Get it: https://claude.ai/code or https://z.ai
|
||||
- ✅ Node.js 18+ installed
|
||||
- Download: https://nodejs.org
|
||||
- ✅ Z.ai Coding Plan, OpenRouter, or Anthropic API key (configured in Claude CLI)
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Extract this package
|
||||
```bash
|
||||
unzip agentic-writer-local-backend.zip
|
||||
cd agentic-writer-local-backend
|
||||
```
|
||||
|
||||
### 2. Start the proxy
|
||||
```bash
|
||||
chmod +x start-proxy.sh
|
||||
./start-proxy.sh
|
||||
```
|
||||
|
||||
You'll see:
|
||||
```
|
||||
═══════════════════════════════════════════════════
|
||||
✅ Local Backend Running!
|
||||
═══════════════════════════════════════════════════
|
||||
|
||||
Your Configuration:
|
||||
Base URL: http://192.168.1.105:8080
|
||||
API Key: dummy
|
||||
Model: glm-4-7
|
||||
```
|
||||
|
||||
### 3. Configure WordPress plugin
|
||||
|
||||
1. Open WP Admin → Agentic Writer → Settings → **Local Backend**
|
||||
2. Paste the **Base URL** shown above
|
||||
3. API Key: `dummy`
|
||||
4. Click **Test Connection** → should show ✅
|
||||
5. Start generating content!
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
./start-proxy.sh # Start proxy (runs in background)
|
||||
./stop-proxy.sh # Stop proxy
|
||||
./test-connection.sh # Test if proxy responds
|
||||
tail -f proxy.log # View real-time logs
|
||||
```
|
||||
|
||||
## Firewall Setup
|
||||
|
||||
### macOS
|
||||
System Settings → Network → Firewall → Options → Add `node` → Allow incoming
|
||||
|
||||
### Linux (ufw)
|
||||
```bash
|
||||
sudo ufw allow 8080/tcp
|
||||
```
|
||||
|
||||
### Windows
|
||||
Windows Defender Firewall → Advanced Settings → Inbound Rules → New Rule → Port 8080
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Connection failed" in plugin
|
||||
- ✅ Check proxy is running: `ps aux | grep claude-proxy`
|
||||
- ✅ Test manually: `./test-connection.sh`
|
||||
- ✅ Check IP is correct: `./get-local-ip.sh`
|
||||
|
||||
### "Claude CLI not found"
|
||||
```bash
|
||||
# Verify Claude is installed
|
||||
which claude
|
||||
claude --version
|
||||
|
||||
# If not found, check installation:
|
||||
# - macOS: /opt/homebrew/bin/claude
|
||||
# - Linux: ~/.local/bin/claude
|
||||
```
|
||||
|
||||
### "No response from Claude"
|
||||
- ✅ Check Claude CLI works: `echo "Hello" | claude`
|
||||
- ✅ Verify Z.ai/API key is configured: `claude --help` (shows auth status)
|
||||
- ✅ Check logs: `tail -f proxy.log`
|
||||
|
||||
### Port 8080 already in use
|
||||
```bash
|
||||
# Find what's using port
|
||||
lsof -i :8080
|
||||
|
||||
# Change port (edit claude-proxy.js)
|
||||
PORT=9000 node claude-proxy.js
|
||||
# Update plugin Base URL: http://your-ip:9000
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Proxy binds to `0.0.0.0` (all interfaces) for LAN access
|
||||
- No authentication by design (LAN trust model)
|
||||
- For internet exposure, use ngrok/reverse proxy with auth
|
||||
- Logs contain request prompts (for debugging)
|
||||
|
||||
## Support
|
||||
|
||||
- Full docs: https://docs.your-site.com/local-backend
|
||||
- Issues: https://github.com/your/plugin/issues
|
||||
- Discord: https://discord.gg/your-server
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Benefits & Use Cases
|
||||
|
||||
### Key Benefits
|
||||
|
||||
1. **Zero API Costs**: Use prepaid Z.ai Coding Plan or existing Anthropic sub
|
||||
2. **Unlimited Generation**: No rate limits, no token counting
|
||||
3. **Privacy**: Content never leaves your network
|
||||
4. **Speed**: LAN latency << internet API calls
|
||||
5. **Offline Ready**: Works without internet (if local WP)
|
||||
6. **Model Flexibility**: Switch Claude models via CLI config
|
||||
|
||||
### Target Use Cases
|
||||
|
||||
| Use Case | Why Local Backend |
|
||||
|----------|------------------|
|
||||
| **High-volume content creation** | Avoid per-token costs, no rate limits |
|
||||
| **Sensitive/NDA content** | Never hits external APIs |
|
||||
| **Development/Testing** | Iterate rapidly without API spend |
|
||||
| **Agency workflows** | One Z.ai account → unlimited client sites |
|
||||
| **Offline scenarios** | Local WP + local AI = fully offline |
|
||||
|
||||
---
|
||||
|
||||
## Technical Considerations
|
||||
|
||||
### Performance
|
||||
|
||||
- **Latency**: ~50-200ms LAN vs ~500-2000ms internet API
|
||||
- **Throughput**: Limited by Claude CLI speed (~20-30 tokens/sec on M1)
|
||||
- **Concurrency**: One request at a time (spawn per request)
|
||||
- **Scalability**: Single-user/dev-team, not multi-tenant SaaS
|
||||
|
||||
### Security
|
||||
|
||||
- **Network**: Runs on LAN, accessible to any device on network
|
||||
- **Authentication**: None (trust LAN devices)
|
||||
- **Logging**: All prompts logged to `proxy.log` (GDPR consideration)
|
||||
- **Recommendation**: Firewall to specific IPs if multi-user network
|
||||
|
||||
### Limitations
|
||||
|
||||
- Requires Node.js on user machine (technical barrier)
|
||||
- User must maintain Claude CLI (updates, auth refresh)
|
||||
- No built-in retry/failover (single point of failure)
|
||||
- Not suitable for public/shared hosting (security)
|
||||
|
||||
---
|
||||
|
||||
## Implementation Checklist
|
||||
|
||||
### Phase 1: Core Proxy (Week 1)
|
||||
- [ ] Create `claude-proxy.js` with `/v1/messages` endpoint
|
||||
- [ ] Add `/ping` health check
|
||||
- [ ] Create `start-proxy.sh` with IP detection
|
||||
- [ ] Create `stop-proxy.sh`
|
||||
- [ ] Create `test-connection.sh`
|
||||
- [ ] Write `README.md` with setup guide
|
||||
- [ ] Package as `agentic-writer-local-backend.zip`
|
||||
|
||||
### Phase 2: Plugin Integration (Week 1)
|
||||
- [ ] Add "Local Backend" settings tab
|
||||
- [ ] Implement ZIP download from plugin settings
|
||||
- [ ] Add Base URL / API Key / Model inputs
|
||||
- [ ] Create AJAX "Test Connection" handler
|
||||
- [ ] Add `LocalBackendProvider` class
|
||||
- [ ] Register provider in provider factory
|
||||
- [ ] Update main generation flow to support local backend
|
||||
|
||||
### Phase 3: Documentation (Week 2)
|
||||
- [ ] Write full setup guide (with screenshots)
|
||||
- [ ] Create video tutorial (5-min screencast)
|
||||
- [ ] Add troubleshooting section to docs
|
||||
- [ ] Create FAQ page
|
||||
- [ ] Add to plugin welcome wizard
|
||||
|
||||
### Phase 4: Polish (Week 2)
|
||||
- [ ] Auto-detect if proxy running (plugin UI indicator)
|
||||
- [ ] Add "Start Proxy" button (launch via system command)
|
||||
- [ ] Connection status widget (green/red indicator)
|
||||
- [ ] Proxy version check (ensure compatibility)
|
||||
- [ ] Error message improvements (actionable guidance)
|
||||
|
||||
### Phase 5: Advanced (Future)
|
||||
- [ ] Multi-model support (detect available Claude models)
|
||||
- [ ] Request queue (handle concurrent generation)
|
||||
- [ ] WebSocket streaming (real-time output)
|
||||
- [ ] Docker image option (one-click deployment)
|
||||
- [ ] Windows .exe wrapper (no Node.js install needed)
|
||||
|
||||
---
|
||||
|
||||
## Success Metrics
|
||||
|
||||
### User Adoption
|
||||
- **Target**: 15% of active users enable Local Backend within 3 months
|
||||
- **Measure**: Track `local_backend_url` option set count
|
||||
|
||||
### Performance
|
||||
- **Target**: <100ms LAN latency for content generation
|
||||
- **Measure**: Log round-trip time in plugin
|
||||
|
||||
### Support
|
||||
- **Target**: <5% support ticket rate for Local Backend setup
|
||||
- **Measure**: Track "Local Backend" tagged tickets
|
||||
|
||||
### Cost Savings
|
||||
- **Target**: 30% reduction in external API spend for heavy users
|
||||
- **Measure**: Compare pre/post API usage in analytics
|
||||
|
||||
---
|
||||
|
||||
## Marketing Angle
|
||||
|
||||
### Positioning
|
||||
**"Unlimited Private AI Content Generation"**
|
||||
|
||||
Run WP Agentic Writer with your own Claude CLI + Z.ai account. Zero per-token costs. Complete privacy. Unlimited throughput.
|
||||
|
||||
### Key Messages
|
||||
- 🚀 **Unlimited**: No rate limits, no token counting, generate 24/7
|
||||
- 🔒 **Private**: Your content never leaves your network
|
||||
- 💰 **Free**: Use existing Z.ai/Anthropic subscription, no extra API costs
|
||||
- ⚡ **Fast**: LAN speed beats internet API latency
|
||||
- 🛠️ **Developer-Friendly**: Full control, local logs, easy debugging
|
||||
|
||||
### Competitive Advantage
|
||||
No other WordPress AI plugin offers seamless local LLM integration with enterprise-grade models (Claude via Z.ai). Competitors force cloud API usage = ongoing costs + privacy concerns.
|
||||
|
||||
---
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
| Risk | Impact | Mitigation |
|
||||
|------|--------|------------|
|
||||
| **Technical barrier** (Node.js install) | Medium | Provide video tutorial, one-click installers (future) |
|
||||
| **Support burden** (networking issues) | Medium | Comprehensive troubleshooting docs, community Discord |
|
||||
| **Security misconfiguration** | Low | Clear warnings in docs, bind to 127.0.0.1 by default option |
|
||||
| **Claude CLI breaking changes** | Low | Version pinning, update notifications |
|
||||
| **User expects 100% uptime** | Low | Docs clearly state "dev/team use, not production SaaS" |
|
||||
|
||||
---
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### V2 Features
|
||||
1. **Auto-start on boot** (launchd/systemd/Task Scheduler)
|
||||
2. **Multi-user support** (API key auth per WP site)
|
||||
3. **Load balancing** (multiple Claude CLI instances)
|
||||
4. **Model switching** (UI to select Claude Opus/Sonnet/Haiku)
|
||||
5. **Monitoring dashboard** (requests/sec, uptime, error rate)
|
||||
|
||||
### V3 Features
|
||||
1. **Docker image** (one-command deployment)
|
||||
2. **GUI app** (macOS/Windows tray icon + config UI)
|
||||
3. **Cloud sync** (fallback to OpenRouter if local offline)
|
||||
4. **Team mode** (shared proxy for agency/team)
|
||||
5. **Plugin marketplace** (middleware for image gen, RAG, etc.)
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
**Local Backend Mode** positions WP Agentic Writer as the only WordPress AI plugin that gives users complete control over their inference stack. By leveraging users' existing Claude CLI + Z.ai setups, we unlock unlimited content generation without sacrificing quality or incurring per-token costs.
|
||||
|
||||
**Differentiator**: Privacy + Cost + Control in one feature.
|
||||
**Target**: Developer-savvy users, agencies, high-volume creators.
|
||||
**Effort**: 2 weeks MVP, ongoing maintenance minimal.
|
||||
|
||||
**Go/No-Go Decision**: ✅ GO
|
||||
- Low implementation cost (10 lines Node.js + settings UI)
|
||||
- High perceived value (unlimited AI = killer feature)
|
||||
- Strong market differentiation (no competitor offers this)
|
||||
- Aligns with dev-first positioning of plugin
|
||||
|
||||
---
|
||||
|
||||
## Appendix
|
||||
|
||||
### File Manifest (Deliverables)
|
||||
|
||||
```
|
||||
WordPress Plugin Files:
|
||||
├── includes/providers/class-local-backend-provider.php
|
||||
├── admin/views/settings-local-backend.php
|
||||
├── admin/js/test-local-backend.js
|
||||
└── downloads/agentic-writer-local-backend.zip
|
||||
├── claude-proxy.js
|
||||
├── start-proxy.sh
|
||||
├── stop-proxy.sh
|
||||
├── test-connection.sh
|
||||
├── get-local-ip.sh
|
||||
├── package.json
|
||||
├── README.md
|
||||
├── TROUBLESHOOTING.md
|
||||
└── examples/
|
||||
└── plugin-config-screenshot.png
|
||||
```
|
||||
|
||||
### Sample Error Messages
|
||||
|
||||
```php
|
||||
// Connection errors with actionable guidance
|
||||
$errors = [
|
||||
'timeout' => 'Connection timeout. Is the proxy running? Check with: ps aux | grep claude-proxy',
|
||||
'refused' => 'Connection refused. Ensure proxy started successfully: ./start-proxy.sh',
|
||||
'wrong_ip' => 'Cannot reach this IP. Run ./get-local-ip.sh to find correct address.',
|
||||
'no_claude' => 'Claude CLI not responding. Test manually: echo "test" | claude',
|
||||
'invalid_response' => 'Proxy returned invalid data. Check logs: tail -f proxy.log'
|
||||
];
|
||||
```
|
||||
|
||||
### Version History
|
||||
|
||||
- **v1.0.0** (Initial): Core proxy + plugin integration
|
||||
- **v1.1.0** (Planned): Auto-start, connection monitoring
|
||||
- **v2.0.0** (Future): Docker image, GUI app, team mode
|
||||
|
||||
---
|
||||
|
||||
**Document Version**: 1.0
|
||||
**Last Updated**: 2026-02-27
|
||||
**Author**: Implementation Brief for WP Agentic Writer
|
||||
**Status**: Ready for Development
|
||||
Reference in New Issue
Block a user