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
# Activate Bilbo Baggins Profile
# FIXED: Starts telegram bot + webhook server + churn
echo "🧙‍♂️ Activating Bilbo Baggins..."
echo "================================"
echo "Activating Bilbo Baggins..."
export HOME=/root/wizards/bilbobagginshire
export HERMES_HOME=/root/wizards/bilbobagginshire/home
export BILBO_MODE=active
cd /root/wizards/bilbobagginshire
# Load environment
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 "Bilbo Status:"
echo " Gitea User: bilbobagginshire"
echo " Repo: bilbobagginshire/bilbo-adventures"
echo " Anthropic OAuth: Configured (401 expected)"
echo " Webhook: Active on localhost:8643"
echo " Admin: Yes (reluctantly)"
echo " Webhook Server: RUNNING (port 8765 - dispatches)"
echo " Telegram Bot: RUNNING (real Ollama)"
echo " Churn: RUNNING"
echo ""
echo "Bilbo is ready for adventure... though he does miss his armchair."
echo ""
echo "To dispatch Bilbo: python3 home/bilbo_dispatcher.py"
echo "Bilbo is back and ready for dispatches."

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()