From 5c79f0baa76e91a53171a8b9df837fdd8ecc72c7 Mon Sep 17 00:00:00 2001 From: inhyoe Date: Sat, 28 Feb 2026 21:34:58 +0900 Subject: [PATCH 1/2] feat: forward unknown /commands to Claude as natural language MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a catch-all handler for unrecognized slash commands (e.g. /commit, /review, /tofu_at) that converts them to natural language prompts and forwards them to Claude via the existing agentic_text handler. This enables project-specific Claude Code slash commands defined in .claude/commands/ to work seamlessly through the Telegram bot without requiring explicit handler registration for each one. Implementation notes: - Registers a COMMAND filter handler at group=10 (after built-in commands) - Converts underscores to hyphens (/tofu_at → /tofu-at) since Telegram bot commands don't support hyphens - Uses an override_text parameter on agentic_text() instead of mutating update.message.text, which is frozen in python-telegram-bot v20+ Co-Authored-By: Claude Opus 4.6 --- src/bot/orchestrator.py | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/src/bot/orchestrator.py b/src/bot/orchestrator.py index faacabb8..961c0c18 100644 --- a/src/bot/orchestrator.py +++ b/src/bot/orchestrator.py @@ -322,6 +322,17 @@ def _register_agentic_handlers(self, app: Application) -> None: group=10, ) + # Unknown commands -> forward to Claude as natural language + # This allows project-specific slash commands (e.g. /commit, /review) + # to be interpreted by Claude as task descriptions. + app.add_handler( + MessageHandler( + filters.COMMAND, + self._inject_deps(self._agentic_unknown_command), + ), + group=10, + ) + # File uploads -> Claude app.add_handler( MessageHandler( @@ -819,12 +830,30 @@ async def _send_images( return caption_sent - async def agentic_text( + async def _agentic_unknown_command( self, update: Update, context: ContextTypes.DEFAULT_TYPE + ) -> None: + """Forward unknown /commands to Claude as natural language. + + Enables project-specific commands like /commit, /review, etc. + to be interpreted by Claude as task descriptions. + """ + message_text = update.message.text + # Convert "/some_cmd args" -> "Run /some-cmd args" for Claude + cmd_text = message_text.replace("_", "-") + prompt = f"Run {cmd_text}" + # Note: Message objects are frozen in python-telegram-bot v20+, + # so we pass the transformed text via override_text parameter + # instead of mutating update.message.text directly. + await self.agentic_text(update, context, override_text=prompt) + + async def agentic_text( + self, update: Update, context: ContextTypes.DEFAULT_TYPE, + override_text: str | None = None, ) -> None: """Direct Claude passthrough. Simple progress. No suggestions.""" user_id = update.effective_user.id - message_text = update.message.text + message_text = override_text or update.message.text logger.info( "Agentic text message", From e4c6b0a893c599cf7c22fdc219bc95d95c21fc51 Mon Sep 17 00:00:00 2001 From: ryu-changhoon Date: Mon, 16 Mar 2026 16:53:10 +0900 Subject: [PATCH 2/2] fix: scope underscore-to-hyphen replacement to command token only Prevents mangling arguments containing underscores (e.g. `/deploy my_service` was incorrectly becoming `Run /deploy my-service`). Co-Authored-By: Claude Opus 4.6 (1M context) --- src/bot/orchestrator.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bot/orchestrator.py b/src/bot/orchestrator.py index 961c0c18..9a3a7a45 100644 --- a/src/bot/orchestrator.py +++ b/src/bot/orchestrator.py @@ -840,8 +840,11 @@ async def _agentic_unknown_command( """ message_text = update.message.text # Convert "/some_cmd args" -> "Run /some-cmd args" for Claude - cmd_text = message_text.replace("_", "-") - prompt = f"Run {cmd_text}" + # Only replace underscores in the command token, not in arguments + parts = message_text.split(maxsplit=1) + cmd = parts[0].replace("_", "-") + args = parts[1] if len(parts) > 1 else "" + prompt = f"Run {cmd} {args}".strip() # Note: Message objects are frozen in python-telegram-bot v20+, # so we pass the transformed text via override_text parameter # instead of mutating update.message.text directly.