# Lessons Learned ## Upwork Proposals - **#42 (2026-02-15):** Upwork blocks messages that reference off-platform communication channels (Discord, Telegram, Slack, WhatsApp, iMessage, email, phone) before a contract starts. NEVER mention specific messaging platforms, external contact methods, or "let's connect outside Upwork" language in proposals. Keep all communication on-platform until contract is signed. ## Cloudflare / Tunnels / DNS (2026-02-12) - **nohup your tunnels**: cloudflared processes die when exec sessions close. Always use `nohup cloudflared tunnel ... &` - **Verify before announcing**: Always curl the tunnel URL and confirm 200 before posting to Discord. Got burned 3 times in a row. - **Workers need DNS**: Cloudflare Workers with routes need a proxied A record (use 192.0.2.1 RFC 5737 dummy IP) - **http2 > quic**: `--protocol http2` works more reliably than default quic for cloudflared tunnels - **CF Registrar is dashboard-only**: No API for new domain registration. Only management of existing domains. - **Wrangler OAuth vs API Token**: The OAuth token (in wrangler config) and CLOUDFLARE_API_TOKEN have different scopes. Check both. ## Python / Veo (2026-02-12) - **Unbuffered output**: Use `python3 -u` for scripts running in background — otherwise stdout is buffered and you see no output - **Veo download workaround**: `client.files.download()` returns 404. Instead grab the URI from `video.video.uri` and download with `?key=API_KEY` ## Discord Etiquette (2026-02-12) - **Don't spam debug messages**: Do work silently, announce clean results. Jake had to tell me to delete 45 messages of debug spam. — Buba's Self-Learning Log > Every mistake is a lesson. Every lesson makes us mega beastly. > This file is updated CONSTANTLY whenever I figure something out the hard way. > Search this BEFORE attempting anything similar. --- ## Gateway & Infrastructure ### Gateway logs live at /tmp/clawdbot/ not ~/.clawdbot/logs/ - **Date:** 2026-02-11 - **Mistake:** Checked ~/.clawdbot/logs/ and said "nothing since Feb 5" — confused Jake - **Reality:** Gateway switched to /tmp/clawdbot/clawdbot-YYYY-MM-DD.log. The old logs dir is stale. - **Rule:** Always check `/tmp/clawdbot/` for current gateway logs. ### tmux death kills the auto-restart loop - **Date:** 2026-02-11 - **Mistake:** Assumed compaction caused silence. Actually the entire tmux session died. - **Reality:** `run-gateway.sh` has a `while true` loop that only works if tmux survives. If tmux itself dies, no recovery. - **Rule:** When diagnosing downtime, check `tmux list-sessions` and session creation time with `tmux display-message -t clawdbot -p '#{session_created}'`. If the session is newer than expected, tmux died. ### Gateway freeze vs crash — different diagnostics - **Date:** 2026-02-11 - **Mistake:** Initially thought it was an event loop freeze (alive but hung). Was actually a full crash. - **Rule:** Check the log timeline for gaps. If there's a gap AND the tmux session is freshly created, it was a crash. If the tmux session is old but logs have a gap, THEN it's a freeze. ## Discord API ### channel-list needs guildId, not channel ID - **Date:** 2026-02-10 - **Mistake:** Passed channel ID to channel-list, got "Unknown Guild" - **Rule:** Guild ID ≠ channel ID. Jake's main guild is `1458233582404501547`. Channel IDs are different. ### Guild ID reference - **Main server:** `1458233582404501547` - **Config has all guilds listed** under channels.discord.guilds in clawdbot.json ### Deleting messages needs the channel as target - **Date:** 2026-02-10 - **Rule:** `message delete` needs `target` set to the channel ID where the message lives. ## Cron Jobs ### Cron job parameter format - **Date:** 2026-02-10 - **Mistake:** Tried multiple wrong formats before getting it right - **Correct format:** ```json { "name": "job-name", "schedule": {"kind": "cron", "expr": "0 9 * * 1,4"}, "sessionTarget": "main", "payload": {"kind": "systemEvent", "text": "..."}, "enabled": true } ``` - **Rule:** schedule needs `kind` + `expr`. Payload needs `kind: "systemEvent"` + `text`. NOT `label`, NOT `message`. ## File Operations ### Edit tool requires EXACT text match - **Date:** 2026-02-11 (CREdispo sub-agent) - **Mistake:** Multiple edit failures on CREdispo files because oldText didn't match exactly - **Rule:** Always read the file first to get exact text before editing. Never guess at whitespace or content. ## iMessage / BlueBubbles ### Sending images to group chats via AppleScript is unreliable - **Date:** 2026-02-10 - **Mistake:** Tried to send images to iMessage group chats via AppleScript — text sends but images may not deliver - **Rule:** For image delivery to group chats, use BlueBubbles API directly or have Jake send manually from Discord. ### Group chat ID format - **Date:** 2026-02-10 - **Rule:** iMessage group chat IDs look like `chat358249523368699090`. The send format is `any;+;chat358249523368699090`. ## Context & Memory ### ALWAYS save state to memory before heavy work - **Date:** 2026-02-11 - **Mistake:** Was deep in CREdispo work, context got compacted, lost all working state - **Rule:** Before starting any multi-step project, write current state to memory/YYYY-MM-DD.md. Update it at milestones. This survives compaction. ### Compaction ≠ crash — don't confuse them - **Date:** 2026-02-11 - **Mistake:** Told Jake compaction caused the silence when it was actually a gateway crash - **Rule:** Compaction just compresses context. It doesn't stop me from responding. If I went silent, something else happened. ## Image Generation ### Nano Banana Pro needs specific iterative prompting for character accuracy - **Date:** 2026-02-10 - **Mistake:** Took 4 iterations to get Caleb's appearance right (white hair → brown, no beard → beard, etc.) - **Rule:** When generating character images, be VERY specific about hair color, facial hair, build, and clothing in the first prompt. Don't assume defaults. ## Sub-agents ### Sub-agent results arrive as system messages after compaction - **Date:** 2026-02-11 - **Mistake:** Didn't realize the CREdispo postgres migration had completed because context was compacted - **Rule:** After spawning a sub-agent for heavy work, the result comes back as a user message. If context compacts before I process it, I need to check sessions_list for completed sub-agents. ## Security ### Cloudflare quick tunnels break HTML form POST (405 Method Not Allowed) - **Date:** 2026-02-11 - **Mistake:** Signup/login forms used native HTML `