Skip to content

fix(composer): send commands and skills the way the harness expands them - #593

Merged
Tryanks merged 1 commit into
mainfrom
fix/composer-slash-triggers
Oct 6, 2026
Merged

Tryanks merged 1 commit into
mainfrom
fix/composer-slash-triggers

Conversation

@Tryanks

@Tryanks Tryanks commented Oct 6, 2026

Copy link
Copy Markdown
Owner

Summary

What the composer sends, before and after, per provider:

 detect_composer_trigger(text, cursor)
-  "/" at the start of any line opens the command menu
+  "/" opens the command menu only at byte 0 of the message
+  "/Users/me/notes.md" (a second "/" in the token) is a path: no menu
 menu_visible()
-  true whenever a trigger is active ("No matching command." + Enter does nothing)
+  true only when the menu has rows ("@" keeps its loading/empty state)
+  → an unmatched "/word" or "$WORD" is plain text and Enter submits it

 wire_text()  (runtime, before the provider sees the turn)
   image-only placeholder
+  native_skill_invocation: leading "$name" → "/name" when the provider lists
+    name as both a skill and a slash command (Claude); Codex keeps "$name"
-  ultrathink: "Ultrathink:\n" + text
+  ultrathink: "Ultrathink:\n" + text, or text + "\n\nultrathink" after a "/command"

 codex provider start
   skills/list → "$" menu
-  ~/.codex/prompts/*.md → "/" menu   (app-server never expanded these)

Why: Claude Code expands a command or skill only when /name is the first byte of the user text; anything else reaches the model as plain text and the model then calls the Skill tool itself. Codex's app-server expands $name in plain text itself and has no API for custom prompts (deprecated upstream).

Evidence

  • Before: typing /Users/me/notes.md opened an empty "No matching command." menu and Enter did nothing; $pongskill to Claude and Ultrathink:\n/pongcmd both produced TOOL-USE: Skill (model-driven), and /pongprompt on Codex made the model cat the prompt file.
    After: same stream-json messages the runtime now produces, driven straight into the CLIs:

    claude  /pongcmd hello            → USER-TEXT: <command-message>pongcmd</command-message>… → PONGCMD
    claude  /pongskill                → USER-TEXT: <command-message>pongskill</command-message>… → PONGSKILL
    claude  /pongcmd hello\n\nultrathink → <command-args>hello\n\nultrathink</command-args> + "ultrathink" system-reminder in the transcript
    codex   Use $pongskill (text_elements: []) → agentMessage: PONGSKILL, no file read
    

    New tests, all passing with the rest of the workspace (889 run, 0 failed):

    tcode-ui      composer_trigger::tests::triggers_respect_token_boundaries_and_the_utf8_cursor
                  composer::components::trigger_menu::tests::unmatched_command_and_skill_tokens_open_no_menu
    tcode-runtime app::tests::skill_mentions_use_the_providers_native_invocation
                  app::tests::ultrathink_keyword_trails_a_slash_command
    

Merge Danger

Door: two-way

Pure client-side behaviour; reverting restores the old trigger rules and wire text.

Blast Radius: composer

Three visible changes for existing users: / on a second line no longer opens the menu; the "No matching command / No skills found" empty states are gone (an unmatched token is just text); Codex users lose ~/.codex/prompts entries from the / menu. A $skill sent to Claude now arrives as /skill, so the bubble shows $skill while the CLI runs the command.

The `/` menu now opens only at the start of the message and never for a
path, and a `/` or `$` token that matches nothing opens no menu, so Enter
submits it instead of being swallowed. A leading `$skill` is sent as
`/skill` when the provider also lists it as a command (Claude), the only
form Claude Code expands; Codex mentions stay `$skill`. The Ultrathink
keyword trails a slash command instead of displacing it from byte 0.
Codex `~/.codex/prompts` entries are no longer offered: the app-server
neither lists nor expands them.
@Tryanks
Tryanks merged commit 7cd617a into main Oct 6, 2026
7 checks passed
@Tryanks
Tryanks deleted the fix/composer-slash-triggers branch October 6, 2026 04:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant