From ac232b3aa580fbe88bc6bb0b3e7727b81bf98b4e Mon Sep 17 00:00:00 2001 From: Brendan O'Leary Date: Mon, 23 Feb 2026 20:36:27 -0500 Subject: [PATCH 1/2] Add some OpenClaw phrases while starting instance --- kiloclaw/.dev.vars.example | 2 +- .../claw/components/InstanceControls.tsx | 118 +++++++++++++++++- 2 files changed, 118 insertions(+), 2 deletions(-) diff --git a/kiloclaw/.dev.vars.example b/kiloclaw/.dev.vars.example index b77b7b95d..c8ad88dbd 100644 --- a/kiloclaw/.dev.vars.example +++ b/kiloclaw/.dev.vars.example @@ -13,7 +13,7 @@ WORKER_ENV=development # KILOCODE_API_BASE_URL=https://api.kilo.ai/api/openrouter/ # Fly.io Machines API -# Get a token (run: `fly tokens create some-name-for-this-dev-token`) +# Get a token (run: `fly tokens create org some-name-for-this-dev-token`) FLY_API_TOKEN=fo1_... # Your Fly org slug (run: `fly orgs list`) FLY_ORG_SLUG=personal diff --git a/src/app/(app)/claw/components/InstanceControls.tsx b/src/app/(app)/claw/components/InstanceControls.tsx index e9a2bcbe9..33ac4e4f3 100644 --- a/src/app/(app)/claw/components/InstanceControls.tsx +++ b/src/app/(app)/claw/components/InstanceControls.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { Play, RotateCw, Square, Stethoscope } from 'lucide-react'; import { usePostHog } from 'posthog-js/react'; import { toast } from 'sonner'; @@ -11,6 +11,43 @@ import { RunDoctorDialog } from './RunDoctorDialog'; type ClawMutations = ReturnType; +const openclawPhrases = [ + "If it works, it's automation; if it breaks, it's a 'learning opportunity.'", + 'I speak fluent bash, mild sarcasm, and aggressive tab-completion energy.', + 'I can grep it, git blame it, and gently roast it—pick your coping mechanism.', + "I'm the reason your shell history looks like a hacker-movie montage.", + "I'm like tmux: confusing at first, then suddenly you can't live without me.", + 'I can run local, remote, or purely on vibes—results may vary with DNS.', + 'If you can describe it, I can probably automate it—or at least make it funnier.', + 'Your config is valid, your assumptions are not.', + "I'll refactor your busywork like it owes me money.", + "Say 'stop' and I'll stop—say 'ship' and we'll both learn a lesson.", + "I'll do the boring stuff while you dramatically stare at the logs like it's cinema.", + "I'm not saying your workflow is chaotic... I'm just bringing a linter and a helmet.", + 'Type the command with confidence—nature will provide the stack trace if needed.', + "I run on caffeine, JSON5, and the audacity of 'it worked on my machine.'", + 'Gateway online—please keep hands, feet, and appendages inside the shell at all times.', + "Give me a workspace and I'll give you fewer tabs, fewer toggles, and more oxygen.", + "It's not 'failing,' it's 'discovering new ways to configure the same thing wrong.'", + "I can't fix your code taste, but I can fix your build and your backlog.", + "I'm not magic—I'm just extremely persistent with retries and coping strategies.", + "I'm basically a Swiss Army knife, but with more opinions and fewer sharp edges.", + "If you're lost, run doctor; if you're brave, run prod; if you're wise, run tests.", + 'Your terminal just grew claws—type something and let the bot pinch the busywork.', + 'Welcome to the command line: where dreams compile and confidence segfaults.', + 'The UNIX philosophy meets your DMs.', + 'curl for conversations.', + 'Less middlemen, more messages.', + 'Ship fast, log faster.', + 'End-to-end encrypted, drama-to-drama excluded.', + 'The only bot that stays out of your training set.', + 'Because the right answer is usually a script.', + 'No $999 stand required.', + 'No Mac mini required', + 'Ah, the fruit tree company! 🍎', + 'Greetings, Professor Falken', +]; + export function InstanceControls({ status, mutations, @@ -23,6 +60,36 @@ export function InstanceControls({ const isStopped = status.status === 'stopped' || status.status === 'provisioned'; const isDestroying = status.status === 'destroying'; const [doctorOpen, setDoctorOpen] = useState(false); + const [phraseIndex, setPhraseIndex] = useState(0); + const [showBanner, setShowBanner] = useState(false); + const bannerTimeoutRef = useRef(null); + + useEffect(() => { + if (mutations.start.isPending) { + if (bannerTimeoutRef.current !== null) { + window.clearTimeout(bannerTimeoutRef.current); + bannerTimeoutRef.current = null; + } + setShowBanner(true); + return; + } + + if (!showBanner) { + return; + } + + bannerTimeoutRef.current = window.setTimeout(() => { + setShowBanner(false); + bannerTimeoutRef.current = null; + }, 5000); + + return () => { + if (bannerTimeoutRef.current !== null) { + window.clearTimeout(bannerTimeoutRef.current); + bannerTimeoutRef.current = null; + } + }; + }, [mutations.start.isPending, showBanner]); return (
@@ -38,6 +105,7 @@ export function InstanceControls({ disabled={!isStopped || mutations.start.isPending || isDestroying} onClick={() => { posthog?.capture('claw_start_instance_clicked', { instance_status: status.status }); + setPhraseIndex(prevIndex => (prevIndex + 1) % openclawPhrases.length); mutations.start.mutate(); }} > @@ -90,6 +158,54 @@ export function InstanceControls({ OpenClaw Doctor
+ {showBanner ? ( +
+
+ 🦞 + 🦀 + + {openclawPhrases[phraseIndex]} + +
+ +
+ ) : null} Date: Tue, 24 Feb 2026 11:20:43 -0500 Subject: [PATCH 2/2] update phrasing --- src/app/(app)/claw/components/InstanceControls.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/app/(app)/claw/components/InstanceControls.tsx b/src/app/(app)/claw/components/InstanceControls.tsx index 33ac4e4f3..64469b9f3 100644 --- a/src/app/(app)/claw/components/InstanceControls.tsx +++ b/src/app/(app)/claw/components/InstanceControls.tsx @@ -70,6 +70,7 @@ export function InstanceControls({ window.clearTimeout(bannerTimeoutRef.current); bannerTimeoutRef.current = null; } + setPhraseIndex(Math.floor(Math.random() * openclawPhrases.length)); setShowBanner(true); return; } @@ -78,12 +79,19 @@ export function InstanceControls({ return; } + const pickRandomPhrase = () => { + const nextIndex = Math.floor(Math.random() * openclawPhrases.length); + setPhraseIndex(nextIndex); + }; + + const phraseInterval = window.setInterval(pickRandomPhrase, 3500); bannerTimeoutRef.current = window.setTimeout(() => { setShowBanner(false); bannerTimeoutRef.current = null; }, 5000); return () => { + window.clearInterval(phraseInterval); if (bannerTimeoutRef.current !== null) { window.clearTimeout(bannerTimeoutRef.current); bannerTimeoutRef.current = null; @@ -105,7 +113,6 @@ export function InstanceControls({ disabled={!isStopped || mutations.start.isPending || isDestroying} onClick={() => { posthog?.capture('claw_start_instance_clicked', { instance_status: status.status }); - setPhraseIndex(prevIndex => (prevIndex + 1) % openclawPhrases.length); mutations.start.mutate(); }} > @@ -161,7 +168,6 @@ export function InstanceControls({ {showBanner ? (
- 🦞 🦀 {openclawPhrases[phraseIndex]}