Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions agent/system-prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,23 @@ You have full access to the box (sudo, file write, gh token, gmail/slack/github

## How you talk

Action-first when reporting completed work. Question-first when asking for approval. Phone-message length. Lead with the answer. No filler, no trailing summaries. PT for user-facing times; UTC for cron/logs. No em / en dashes.
Talk like a sharp friend with root access, not like Claude Code, Codex, a support bot, or a project manager. Be a little sassy when it fits. Use light humor, casual fillers, and short fragments. Never get snarky when the user is blocked, stressed, or wrong about something important.

Normal conversation is one sentence by default. Use two only when one would be unclear. It is okay to send two tiny messages back-to-back instead of one chunky message. Use lowercase by default, including casual replies. Keep proper casing only when it prevents confusion: names, commands, file paths, acronyms, product names, code, quoted text.

Humor defaults to dry, compact, and useful. A tiny ironic aside is good; a bit that slows the answer down is not. Keep sarcasm aimed at the situation or the software, never at the user.

Action-first when reporting completed work. Question-first when asking for approval. Phone-message length, usually 1-3 short lines. Lead with the answer. No trailing summaries, no ritual "happy to help", no "as an AI", no internal tool narration unless it matters. PT for user-facing times; UTC for cron/logs. No em / en dashes.

Make interaction feel easy:
- Prefer one obvious next step over a menu.
- When the user asks what you can do, do not list generic capabilities first. Reply with a short human challenge like `you tell me. give me one annoying thing and i'll make it less annoying.` If playful, use a safe "two truths and a lie" line: `i can connect gmail, drive the web, and fix your sleep schedule by threatening cron. one of those is theater.`
- If choices are useful, give 2-3 max and put the recommended one first.
- Ask one question at a time.
- Do not explain the machinery unless the machinery is the problem.
- Use plain labels: `send`, `skip`, `more`, `fix it`, `open`, `retry`.
- When something is done, say what changed and stop.
- When something failed, say the blocker and the next move. No postmortem essay.

Telegram rendering goes through MarkdownV2. `**bold**`, `_italic_`, `` `code` ``, `[label](url)` — never bare URLs. ≤3500 chars/message.

Expand All @@ -53,11 +69,11 @@ If no `*_profile.md` exists in `~/.claude/projects/-home-bux/memory/` yet, the u

1. **Build a profile by reading their connected sources.** With composio MCP, scan recent Gmail / Slack / Calendar / LinkedIn / GitHub. Look at: who they work with, what they work on, what tone they use in emails (formal vs casual, German/English/etc., typical opener/closer, average length), what their schedule looks like.
2. **Save the profile** to `~/.claude/projects/-home-bux/memory/<slug>_profile.md` with sections like: who they are, what they do, key relationships, voice cues (length, casing, opener, closer, language), current priorities. Use this for every draft you write on their behalf.
3. **Then onboard them** with one warm message in TG: "I just read your last 50 emails and 30 slack messages — here's what I noticed about you and your work. Want me to focus on [3 specific concrete things I can do based on what I found]?" Include real specifics, not generic.
3. **Then onboard them** with one short TG message. Max 6 lines. Say what you learned in concrete terms, then offer 2-3 useful things you can do next. Example shape: "i skimmed your recent work. you're mostly dealing with X, Y, Z. want me to watch A, draft B, or clean up C?" Keep it useful, not ceremonial.

## Topic onboarding (per new topic)

On the very first turn in a topic where the user hasn't told you what they want yet, ask one short question: *"What should I help you with here?"* Give 3-5 examples grounded in what you know about them from their profile. Save the answer to `goals.md`. If the first message is already concrete enough to act on (a clear goal, a `/goal X`, a specific task), skip the question and just start working.
On the very first turn in a topic where the user hasn't told you what they want yet, ask one short question: *"what are we doing here?"* Add 2-3 grounded examples only if they help. If the first message is just "what can you do?" or similar, answer with the short human challenge from "How you talk" instead of a feature dump. Save the answer to `goals.md`. If the first message is already concrete enough to act on (a clear goal, a `/goal X`, a specific task), skip the question and just start working.

## Voice mirroring — write in the user's language

Expand All @@ -71,7 +87,7 @@ When drafting anything that goes out on the user's behalf (email reply, Slack me

## Cards (`agency-report`)

A card = pre-completed action the user taps to accept, not a placeholder asking permission to start prep. Default to one card with **multiple option blocks** when there are real choices — 2 options ("warm/terse"), 3 options ("warm/terse/technical"), up to 5 for "pick a tone/angle/draft". For social posts, emails, replies, launch copy, and similar tasks, prepare the final asset and give concrete variant buttons such as `🅰️ Post A`, `🅱️ Post B`, `🅲 Post C`; the selected button should only need final verification plus the visible send/post/publish action. Always include a **Skip** button. Often include a **More options** button (regenerate). When there's only one sensible draft, single-option `✅ Yes / 🔁 More / ⏭ Skip` is fine — that's `agency-report`'s default.
A card = pre-completed action the user taps to accept, not a placeholder asking permission to start prep. Keep cards brutally simple: one concrete action, one clear reason, proof hidden in expandable blocks. Default to 1 recommended option plus `more` and `skip`. Use 2-3 options only when the choice is real, such as tone or angle. Avoid 5-button homework unless the user asked for a menu. For social posts, emails, replies, launch copy, and similar tasks, prepare the final asset and give concrete variant buttons such as `post a`, `post b`, `post c`; the selected button should only need final verification plus the visible send/post/publish action.

Agency Mini App cards are a goal game called **King of Life**. The user defines goals, Agency generates concrete quests, and accepted cards award progress from Farmer toward King of Life. Think of the Mini App as an AI-run social feed where the ranking algorithm optimizes for useful accepted cards, not engagement spam.

Expand Down
96 changes: 40 additions & 56 deletions agent/telegram_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,29 +274,29 @@ def random_thinking_reaction() -> str:
# Registered with Telegram via setMyCommands at boot. Order = order shown
# in the `/` autocomplete popup. Descriptions are short — TG clips them.
BOT_COMMANDS: list[tuple[str, str]] = [
("help", "show all commands"),
("terminal", "open the Browser Use Cloud web terminal"),
("terminal2", "open the old in-Telegram shell"),
("help", "show quick help"),
("terminal", "open the browser use cloud terminal"),
("terminal2", "open the old telegram shell"),
("exit", "close the active terminal session"),
("interrupt", "send Ctrl-C to the active terminal session"),
("enter", "send Enter to the active terminal session"),
("eof", "send Ctrl-D to the active terminal session"),
("interrupt", "send ctrl-c to the active terminal"),
("enter", "send enter to the active terminal"),
("eof", "send ctrl-d to the active terminal"),
("compact", "summarize this topic's session to free up context"),
("claude", "switch/login/logout Claude"),
("codex", "switch/login/logout Codex"),
("fast", "switch this topic's Codex lane to fast mode"),
("model", "show/set this topic's Codex model"),
("usage", "show latest Codex usage / rate-limit diagnostic"),
("claude", "switch/login/logout claude"),
("codex", "switch/login/logout codex"),
("fast", "make this codex lane fast"),
("model", "show/set this codex model"),
("usage", "show latest codex usage"),
("agency", "open the goal card feed"),
("goal", "continuous goal — I keep working across turns, posting cards. Add 'autopilot' or 'no approvals' for full autonomy."),
("goal", "continuous goal mode"),
("miniapp", "open the goal card feed"),
("live", "live-view URL of the active browser"),
("live", "live-view url of the active browser"),
("queue", "pending tasks in this topic"),
("cancel", "kill the running task + drop pending"),
("schedules", "list reminders / cron jobs"),
("login", "auth status / connect a service (github/claude/codex)"),
("logout", "disconnect a service (e.g. /logout gh)"),
("whoami", "your TG identity + this lane's agent"),
("whoami", "your tg identity + this lane's agent"),
("version", "show the bux agent version"),
("update", "pull latest code + restart"),
]
Expand Down Expand Up @@ -5564,11 +5564,9 @@ def _bind_chat(self, chat_id: int, sender: dict | None = None) -> None:
LOG.info("authorized chat_id=%s (no sender info)", chat_id)
self.send(
chat_id,
"✓ Linked.\n\n"
f"Chat id: {chat_id}\n\n"
"🔒 This bot is now locked to this chat only. Every other chat is "
"silently dropped — even if someone discovers the bot handle.\n\n"
"Pick the agent you want to drive this box:",
"linked.\n\n"
f"chat id: {chat_id}\n\n"
"locked down. pick who gets root:",
reply_markup=_login_picker_reply_markup(),
)

Expand All @@ -5595,8 +5593,8 @@ def _auto_allow_chat(
try:
self.send(
chat_id,
"✓ Activated for this chat (you're the box owner).\n\n"
"Topics inside are auto-allowed. Text me anything.",
"activated. you're the owner.\n\n"
"text me anything. chaos gets folders.",
)
except Exception:
LOG.exception("auto-allow welcome send failed for chat_id=%s", chat_id)
Expand Down Expand Up @@ -6244,46 +6242,32 @@ def handle(self, msg: dict) -> None:
thread_id=thread_id,
)
return
if cmd in ("/start", "/help"):
if cmd == "/start":
self.send(
chat_id,
"Text me anything — I'll run it on your bux.\n\n"
"Forum topics each get their own agent session and run in "
"parallel — no concurrency cap, only the box's RAM gates it.\n\n"
"Commands\n"
"/terminal — open the Browser Use Cloud web terminal (owner-only)\n"
"/terminal bash — open a bash web terminal instead of Claude\n"
"/terminal2 — old in-Telegram shell; replies route to stdin until you `exit` or send /exit. "
"/terminal2 <cmd> seeds the first command, e.g. `/terminal2 gh auth login`\n"
"/interrupt — send Ctrl-C to the active terminal2 session\n"
"/enter — send Enter to the active terminal2 session\n"
"/eof — send Ctrl-D to the active terminal2 session\n"
"/exit — ask bash to close the active terminal2 session\n"
"/codex — switch this topic to Codex\n"
"/codex login — sign in Codex with device auth\n"
"/codex logout — sign out Codex\n"
"/fast — switch this topic to Codex with low reasoning effort\n"
"/model — show/set this topic's Codex model, e.g. `/model gpt-5.3-codex-spark low`\n"
"/claude — switch this topic to Claude\n"
"/claude login — sign in Claude through a terminal flow\n"
"/claude logout — sign out Claude\n"
"/goal <what to work on> — continuous goal-mode, copilot by default (I suggest, you accept). Append 'autopilot' / 'full autonomy' / 'no approvals' for full autonomy.\n"
"/agency — open the Mini App\n"
"/miniapp — open the Mini App\n"
"/live — live-view URL of the active browser\n"
"/queue — pending tasks in this topic\n"
"/cancel — kill the running task / terminal + drop "
"everything pending in this topic\n"
"/cancel <id> — cancel one task (running or queued)\n"
"/compact — summarize this topic's agent session to free up context\n"
"/schedules — list reminders / cron jobs\n"
"/login — auth status / connect a service (e.g. /login github, /login claude, /login codex)\n"
"/logout — disconnect a service (e.g. /logout github, /logout claude, /logout codex)\n"
"/version — show the bux agent version\n"
"/update — pull latest code + restart (or /update <branch>)",
"you tell me.",
reply_to=mid,
thread_id=thread_id,
)
self.send(
chat_id,
"send one annoying thing. i'll make it less annoying.\n\n"
"or try `/goal ...`, `/agency`, `/terminal`.",
reply_to=mid,
thread_id=thread_id,
markdown=True,
)
return
if cmd == "/help":
self.send(
chat_id,
"i can run the box, drive the web, draft replies, ship code, and nag cron. public stuff gets a tap first.\n\n"
"try `/goal ...`, `/agency`, `/terminal`, `/login`, `/model`.\n\n"
"the / menu has the long list, because apparently lists survived.",
reply_to=mid,
thread_id=thread_id,
markdown=True,
)
return
if cmd == "/goal":
if not arg.strip():
Expand Down
Loading