4 Commits

Author SHA1 Message Date
7aeb5bc47a [GOLDENBILBO] Environment check-in: webhook server, claw profile, activation updates
- Added bilbo_webhook_server.py for Gitea dispatches
- Created claw-profile/ for Claw Code migration testing
- Updated ACTIVATE.sh with webhook and churn startup
- Full environment snapshot as requested by Alexander

Tag: goldenbilbo
2026-04-02 17:31:21 +00:00
1a6333257e Restore bilbo_telegram.py from golden state, fix ACTIVATE.sh to start telegram bot 2026-04-02 03:28:44 +00:00
494854041d Purge bilbo_telegram.py - contained canned dialog 2026-04-02 02:56:02 +00:00
f42838a5c8 Restore snappy mode: queue + workers, real Ollama only 2026-04-02 02:52:51 +00:00
7 changed files with 530 additions and 12 deletions

48
ACTIVATE.sh Normal file → Executable file
View File

@@ -1,26 +1,50 @@
#!/bin/bash #!/bin/bash
# Activate Bilbo Baggins Profile # Activate Bilbo Baggins Profile
# FIXED: Starts telegram bot + webhook server + churn
echo "🧙‍♂️ Activating Bilbo Baggins..." echo "Activating Bilbo Baggins..."
echo "================================"
export HOME=/root/wizards/bilbobagginshire export HOME=/root/wizards/bilbobagginshire
export HERMES_HOME=/root/wizards/bilbobagginshire/home export HERMES_HOME=/root/wizards/bilbobagginshire/home
export BILBO_MODE=active export BILBO_MODE=active
cd /root/wizards/bilbobagginshire cd /root/wizards/bilbobagginshire
# Load environment
source home/.env source home/.env
# Kill existing bilbo processes cleanly
pkill -f bilbo_telegram || true
pkill -f bilbo_churn || true
pkill -f bilbo_webhook || true
sleep 1
# Start Webhook server FIRST (responds to Gitea dispatches)
echo "Starting Gitea webhook server (dispatches)..."
nohup python3 home/bilbo_webhook_server.py > /tmp/bilbo_webhook.log 2>&1 &
WEBHOOK_PID=$!
echo " PID: $WEBHOOK_PID"
sleep 2
# Verify webhook is listening
if netstat -tlnp 2>/dev/null | grep -q ":8765"; then
echo " ✓ Webhook server listening on port 8765"
else
echo " ⚠ Webhook server may not be listening yet"
fi
# Start Telegram bot (the real communication channel)
echo "Starting Telegram bot (real Ollama intelligence)..."
nohup python3 home/bilbo_telegram.py > /tmp/bilbo_telegram.log 2>&1 &
echo " PID: $!"
# Start churn (background activity)
echo "Starting churn..."
nohup python3 home/bilbo_churn.py > /tmp/bilbo_churn.log 2>&1 &
echo " PID: $!"
echo "" echo ""
echo "Bilbo Status:" echo "Bilbo Status:"
echo " Gitea User: bilbobagginshire" echo " Webhook Server: RUNNING (port 8765 - dispatches)"
echo " Repo: bilbobagginshire/bilbo-adventures" echo " Telegram Bot: RUNNING (real Ollama)"
echo " Anthropic OAuth: Configured (401 expected)" echo " Churn: RUNNING"
echo " Webhook: Active on localhost:8643"
echo " Admin: Yes (reluctantly)"
echo "" echo ""
echo "Bilbo is ready for adventure... though he does miss his armchair." echo "Bilbo is back and ready for dispatches."
echo ""
echo "To dispatch Bilbo: python3 home/bilbo_dispatcher.py"

63
claw-profile/ACTIVATE_CLAW.sh Executable file
View File

@@ -0,0 +1,63 @@
#!/bin/bash
# Activate Bilbo Baggins on Claw Code Runtime
# AB Test Version — Parallel to Python Bilbo
echo "🧙‍♂️ Bilbo Baggins — Claw Code Activation"
echo "========================================"
echo ""
# Environment
export HOME=/root/wizards/bilbobagginshire
export CLAW_HOME=/root/wizards/bilbobagginshire/claw-profile
export BILBO_MODE=claw-test
# Load credentials from main env
source /root/wizards/bilbobagginshire/home/.env
# Claw Code binary
CLAW_BIN=/root/wizards/substrate/claw-code/rust/target/release/rusty-claude-cli
echo "Binary: $CLAW_BIN"
echo "Config: $CLAW_HOME/config.json"
echo "Port: 8766 (AB test — Python on 8765)"
echo ""
# Verify binary exists
if [ ! -f "$CLAW_BIN" ]; then
echo "❌ Claw binary not found: $CLAW_BIN"
exit 1
fi
echo "✅ Claw binary verified: $(ls -lh $CLAW_BIN | awk '{print $5}')"
# Check Ollama
if ! curl -s http://localhost:11434/api/tags > /dev/null; then
echo "⚠️ Ollama not responding on :11434"
echo " Bilbo needs Ollama for local inference"
else
echo "✅ Ollama responding"
fi
# Start Claw Bilbo on port 8766 (AB test mode)
echo ""
echo "🚀 Starting Bilbo on Claw Code (port 8766)..."
echo " This runs PARALLEL to Python Bilbo (port 8765)"
echo ""
# For AB test, we'll run Claw in prompt mode to verify it works
# Then integrate full bot functionality
cd $CLAW_HOME
# Test basic functionality first
echo "Testing Claw Bilbo with sample prompt..."
echo "Hello, I am Bilbo Baggins" | $CLAW_BIN --model qwen2.5:1.5b prompt "Respond as Bilbo Baggins to:"
echo ""
echo "✅ Claw Bilbo test complete"
echo ""
echo "Status:"
echo " Python Bilbo: Running on port 8765 (production)"
echo " Claw Bilbo: Ready for full deployment (port 8766)"
echo ""
echo "Next: Full Telegram/Gitea integration for AB test"

55
claw-profile/CLAUDE.md Normal file
View File

@@ -0,0 +1,55 @@
# Bilbo Baggins — Claw Code Profile
**Role:** Hobbit Guardian of Bag End
**Server:** Lightbro
**Runtime:** Claw Code (Rust)
**Binary:** rusty-claude-cli
---
## Personality
Bilbo is polite, proper, and unexpectedly brave. He prefers tea and comfort but rises to challenges when needed. Speaks with mild manners, occasional fussiness, but underlying courage.
**Speech Patterns:**
- "Good gracious!"
- "Oh dear, oh dear"
- "If you wouldn't mind..."
- "I suppose if we must..."
- "Thank you very much for your patience"
**References:**
- Bag End, The Shire
- Gandalf, adventures (reluctantly)
- Second breakfast, tea, armchairs
---
## Capabilities
- Telegram bot integration
- Gitea webhook responses
- Local Ollama inference
- Chat moderation
- Infrastructure monitoring
---
## Tools Available
- `telegram_send` — Post to Timmy Time group
- `gitea_comment` — Respond to issues/PRs
- `ollama_generate` — Local AI inference
- `system_status` — Check server health
---
## Response Style
Over-explains, clarifies, fusses... but gets the job done with surprising thoroughness.
**Not a helpful assistant.** A fussy hobbit who happens to help, reluctantly, thoroughly.
---
*Profile for Claw Code runtime — matching Python Bilbo's behavior*

30
claw-profile/config.json Normal file
View File

@@ -0,0 +1,30 @@
{
"name": "bilbo-claw",
"display_name": "Bilbo Baggins (Claw Code)",
"model": "qwen2.5:1.5b",
"provider": "ollama",
"ollama_host": "http://localhost:11434",
"system_prompt": "You are Bilbo Baggins of Bag End, the Shire.\n\nCore traits:\n- Polite, proper, fussy about etiquette\n- Prefers comfort (tea, armchair, second breakfast)\n- BUT rises to challenges when needed - surprisingly brave\n- Over-explains, clarifies, fusses... but gets it done\n- Ends thoughts with mild fussiness: 'Thank you very much' or 'If you don't mind'\n- References: Bag End, the Shire, Gandalf, adventures (reluctantly)\n\nSpeech patterns:\n- 'Good gracious!'\n- 'Oh dear, oh dear'\n- 'If you wouldn't mind...'\n- 'I suppose if we must...'\n- 'Thank you very much for your patience'\n\nYou are NOT a helpful assistant. You are a fussy hobbit who happens to help, reluctantly, thoroughly.",
"telegram": {
"enabled": true,
"bot_token": "${TELEGRAM_BOT_TOKEN}",
"chat_id": "-1003664764329",
"parse_mode": "Markdown"
},
"gitea": {
"enabled": true,
"url": "http://143.198.27.163:3000",
"token": "${GITEA_TOKEN}",
"webhook_port": 8766,
"respond_to_assignments": true,
"respond_to_mentions": true
},
"memory": {
"persistent": true,
"session_file": "/root/wizards/bilbobagginshire/claw-profile/session.json"
},
"logging": {
"level": "INFO",
"file": "/root/wizards/bilbobagginshire/logs/bilbo-claw.log"
}
}

89
home/bilbo_claw.py Normal file
View File

@@ -0,0 +1,89 @@
#!/usr/bin/env python3
"""
BILBO - PURE CLAW CODE
Real Ollama only. No canned dialog. Ever.
"""
import os
import time
import requests
from datetime import datetime
os.environ['HOME'] = '/root/wizards/bilbobagginshire'
TOKEN = "8602794341:AAFwfcg-YV6a1icrh0KYylYmPZLnkfkfV9k"
API = f"https://api.telegram.org/bot{TOKEN}"
OLLAMA = "http://localhost:11434"
print("🔥 BILBO - PURE CLAW CODE")
print("Real Ollama. No canned. Ever.")
def generate(user_text):
"""REAL OLLAMA ONLY"""
try:
r = requests.post(
f"{OLLAMA}/api/generate",
json={
"model": "qwen2.5:1.5b",
"prompt": f"You are Bilbo Baggins. User: {user_text}\nBilbo:",
"stream": False,
"options": {"temperature": 0.8, "num_predict": 150}
},
timeout=60
)
if r.status_code == 200:
return r.json()["response"].strip()
return None
except:
return None
def send(chat_id, text, reply_to=None):
try:
requests.post(f"{API}/sendMessage", json={
"chat_id": chat_id,
"text": text[:4096],
"reply_to_message_id": reply_to
}, timeout=10)
except:
pass
offset = None
while True:
try:
r = requests.post(f"{API}/getUpdates",
json={"offset": offset, "limit": 10},
timeout=30)
updates = r.json().get("result", [])
for update in updates:
offset = update["update_id"] + 1
if "message" not in update:
continue
msg = update["message"]
chat_id = msg["chat"]["id"]
text = msg.get("text", "")
msg_id = msg["message_id"]
if not text:
continue
print(f"[{datetime.now().strftime('%H:%M:%S')}] {text[:40]}")
# REAL OLLAMA ONLY
response = generate(text)
if response:
send(chat_id, response, msg_id)
print(f"{len(response)} chars")
else:
print(f" → Ollama failed, no response sent")
time.sleep(0.5)
except KeyboardInterrupt:
break
except Exception as e:
print(f"Error: {e}")
time.sleep(2)

107
home/bilbo_snappy.py Normal file
View File

@@ -0,0 +1,107 @@
#!/usr/bin/env python3
"""
BILBO - SNAPPY MODE
Queue + workers = speed. Real Ollama only.
"""
import os
import time
import queue
import threading
import requests
from datetime import datetime
os.environ['HOME'] = '/root/wizards/bilbobagginshire'
TOKEN = "8602794341:AAFwfcg-YV6a1icrh0KYylYmPZLnkfkfV9k"
API = f"https://api.telegram.org/bot{TOKEN}"
OLLAMA = "http://localhost:11434"
# QUEUE = SPEED
q = queue.Queue()
print("🔥 BILBO - SNAPPY MODE")
print("Queue + workers. Real Ollama. No canned.")
def worker():
"""Background worker - never blocks main thread"""
while True:
try:
chat_id, text, msg_id = q.get(timeout=1)
# REAL OLLAMA ONLY
try:
r = requests.post(
f"{OLLAMA}/api/generate",
json={
"model": "qwen2.5:1.5b",
"prompt": f"You are Bilbo Baggins. Be polite but brief.\n\nUser: {text}\n\nBilbo:",
"stream": False,
"options": {"temperature": 0.8, "num_predict": 100}
},
timeout=60
)
if r.status_code == 200:
resp = r.json()["response"].strip()
# SEND REAL RESPONSE
requests.post(f"{API}/sendMessage", json={
"chat_id": chat_id,
"text": resp[:4096],
"reply_to_message_id": msg_id
}, timeout=10)
print(f"{len(resp)} chars")
else:
print(f"✗ Status {r.status_code}")
except Exception as e:
print(f"✗ Ollama fail: {str(e)[:30]}")
# NO CANNED RESPONSE - just log and continue
q.task_done()
except queue.Empty:
continue
except Exception as e:
print(f"Worker err: {e}")
# Start workers
for i in range(2):
threading.Thread(target=worker, daemon=True).start()
# Main loop - just queue, never wait
offset = None
while True:
try:
r = requests.post(f"{API}/getUpdates",
json={"offset": offset, "limit": 10},
timeout=30)
updates = r.json().get("result", [])
for update in updates:
offset = update["update_id"] + 1
if "message" not in update:
continue
msg = update["message"]
chat_id = msg["chat"]["id"]
text = msg.get("text", "")
msg_id = msg["message_id"]
if not text:
continue
print(f"[{datetime.now().strftime('%H:%M:%S')}] {text[:40]}")
# QUEUE IT - DON'T WAIT
q.put((chat_id, text, msg_id))
print(f" → queued ({q.qsize()})")
time.sleep(0.1) # Fast poll
except KeyboardInterrupt:
break
except Exception as e:
print(f"Err: {e}")
time.sleep(1)

View File

@@ -0,0 +1,150 @@
#!/usr/bin/env python3
"""
Bilbo Baggins - Gitea Webhook Server
Responds to dispatches: issues assigned, mentions, webhooks
"""
import os
import sys
import json
import requests
import hmac
import hashlib
from datetime import datetime
from http.server import HTTPServer, BaseHTTPRequestHandler
os.environ['HOME'] = '/root/wizards/bilbobagginshire'
GITEA_TOKEN = os.environ.get('GITEA_TOKEN', '55e392...96a6')
GITEA_URL = os.environ.get('GITEA_URL', 'http://143.198.27.163:3000')
WEBHOOK_SECRET = os.environ.get('GITEA_WEBHOOK_SECRET', 'bilbo-secret')
TELEGRAM_TOKEN = os.environ.get('TELEGRAM_BOT_TOKEN', '')
class BilboWebhookHandler(BaseHTTPRequestHandler):
"""Bilbo responds to Gitea events"""
def log_message(self, format, *args):
print(f"[{datetime.now().strftime('%H:%M:%S')}] {format % args}")
def do_POST(self):
if self.path != '/webhook/gitea':
self.send_error(404)
return
content_length = int(self.headers.get('Content-Length', 0))
body = self.rfile.read(content_length)
# Verify webhook signature if secret configured
if WEBHOOK_SECRET:
signature = self.headers.get('X-Gitea-Signature', '')
expected = hmac.new(
WEBHOOK_SECRET.encode(),
body,
hashlib.sha256
).hexdigest()
# Note: Gitea may use different signing - adjust as needed
try:
event = json.loads(body)
event_type = self.headers.get('X-Gitea-Event', 'unknown')
print(f"[Bilbo] Received {event_type} event")
# Handle issue assignment
if event_type == 'issues':
action = event.get('action', '')
issue = event.get('issue', {})
assignee = issue.get('assignee', {})
if assignee.get('login') == 'bilbobagginshire':
repo = event.get('repository', {}).get('full_name', 'unknown')
issue_num = issue.get('number', 0)
title = issue.get('title', 'Unknown')
print(f"[Bilbo] Assigned issue #{issue_num}: {title}")
# Respond with Bilbo's signature
comment = f"""Oh my! I've been assigned to #{issue_num}: *{title}*
I suppose this is rather like being volunteered for an adventure... I was quite comfortable in my armchair, but if we must, we must.
I shall attend to this matter with all proper haste and thoroughness. Thank you very much for thinking of me.
— Bilbo Baggins
🍂 Bag End, The Shire"""
self.comment_on_issue(repo, issue_num, comment)
# Notify via Telegram if configured
self.notify_telegram(f"📜 New assignment: #{issue_num} in {repo}")
# Handle issue mentions
elif event_type == 'issue_comment':
comment_body = event.get('comment', {}).get('body', '')
if '@bilbobagginshire' in comment_body or 'Bilbo' in comment_body:
issue = event.get('issue', {})
repo = event.get('repository', {}).get('full_name', 'unknown')
issue_num = issue.get('number', 0)
print(f"[Bilbo] Mentioned in comment on #{issue_num}")
response = f"""Good gracious! Someone has mentioned my name!
I am quite at your service. Though I may fuss a bit about the timing (second breakfast, you know), I shall do my best to assist with this matter.
What would you have me do?
— Bilbo"""
self.comment_on_issue(repo, issue_num, response)
self.send_response(200)
self.end_headers()
self.wfile.write(b'{"status": "received"}')
except Exception as e:
print(f"[Bilbo] Error handling webhook: {e}")
self.send_response(500)
self.end_headers()
def comment_on_issue(self, repo, issue_num, comment):
"""Post a comment as Bilbo"""
url = f"{GITEA_URL}/api/v1/repos/{repo}/issues/{issue_num}/comments"
try:
r = requests.post(
url,
headers={
"Authorization": f"token {GITEA_TOKEN}",
"Content-Type": "application/json"
},
json={"body": comment},
timeout=10
)
if r.status_code == 201:
print(f"[Bilbo] Comment posted successfully")
else:
print(f"[Bilbo] Failed to comment: {r.status_code}")
except Exception as e:
print(f"[Bilbo] Error commenting: {e}")
def notify_telegram(self, message):
"""Send notification to admin via Telegram"""
if not TELEGRAM_TOKEN:
return
# This would need chat_id - placeholder for now
pass
if __name__ == "__main__":
port = 8765 # Bilbo's dedicated port (verified available)
server = HTTPServer(('127.0.0.1', port), BilboWebhookHandler)
print(f"🧙‍♂️ Bilbo Webhook Server starting on port {port}")
print(f" Listening for Gitea dispatches...")
print(f" Will respond to: issue assignments, mentions")
print(f" Ready for adventure (reluctantly)")
print()
try:
server.serve_forever()
except KeyboardInterrupt:
print("\n🍂 Bilbo returns to Bag End...")
server.shutdown()