Skip to content

fix: show user messages starting with skill/command invocations in transcript#208

Merged
wesm merged 1 commit intowesm:mainfrom
tlmaloney:fix/skill-invocation-messages
Mar 24, 2026
Merged

fix: show user messages starting with skill/command invocations in transcript#208
wesm merged 1 commit intowesm:mainfrom
tlmaloney:fix/skill-invocation-messages

Conversation

@tlmaloney
Copy link
Copy Markdown
Contributor

@tlmaloney tlmaloney commented Mar 21, 2026

Summary

  • User messages containing <command-message>/<command-name> XML tags (skill invocations like /roborev-fix 450) were incorrectly filtered out by isClaudeSystemMessage, causing sessions started with a slash command to show no first user message
  • Extracts command name and arguments into readable text (e.g. /roborev-fix 450) and displays them as normal user messages
  • Only matches pure command XML envelopes (no trailing prose), with fallback for bare <command-message>-only entries and safe skipping of unrecognized envelopes
  • Removes matching frontend filter in MessageList.svelte
  • Bumps dataVersion to 5 so existing databases automatically resync

Fixes #206

Test plan

  • TestExtractCommandText — 9 cases covering both envelope formats, with/without args, prose false positives, bare fallback
  • TestIsClaudeSystemMessage — updated to verify command tags are no longer filtered
  • TestParseClaudeSession_SkippedMessages — integration tests for skill invocations appearing as user messages
  • Full parser test suite passes
  • Manual verification: start a session with a slash command, confirm the command appears as the first user message in the transcript

🤖 Generated with Claude Code

@roborev-ci
Copy link
Copy Markdown

roborev-ci bot commented Mar 21, 2026

roborev: Combined Review (8aad898)

Summary Verdict: One medium-severity parsing issue was identified regarding Claude command XML extraction; otherwise, the changes are clean and free of security issues.

Medium

  • Location: internal/parser/claude. go:19-22, internal/parser/claude.go:879-915
  • Problem: extractCommandText and isCommandEnvelope only match tag bodies with [^<]* / [^<]+. If a command name or argument
    contains a literal < character, the parser will fail to normalize the envelope. Because this change also stops filtering <command-message> / <command-name> messages, those cases will now leak raw XML into transcripts instead of showing the intended /command ... text.
  • Fix: Parse the command envelope
    with a more permissive approach that allows arbitrary tag contents, such as a non-greedy (?s) match or a small XML parser, and add a regression test covering args that include < / >.

Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

@tlmaloney
Copy link
Copy Markdown
Contributor Author

roborev: Combined Review (8aad898)

Summary Verdict: One medium-severity parsing issue was identified regarding Claude command XML extraction; otherwise, the changes are clean and free of security issues.

Medium

  • Location: internal/parser/claude. go:19-22, internal/parser/claude.go:879-915
  • Problem: extractCommandText and isCommandEnvelope only match tag bodies with [^<]* / [^<]+. If a command name or argument
    contains a literal < character, the parser will fail to normalize the envelope. Because this change also stops filtering <command-message> / <command-name> messages, those cases will now leak raw XML into transcripts instead of showing the intended /command ... text.
  • Fix: Parse the command envelope
    with a more permissive approach that allows arbitrary tag contents, such as a non-greedy (?s) match or a small XML parser, and add a regression test covering args that include < / >.

Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

Saw this from Codex, and Claude responded reasonably: "Command names/args from Claude Code are plain identifiers and short text strings -- they never contain literal < characters. Per project guideline #10, input files are from local agent CLIs, not adversarial. Using a full XML parser would be over-engineering for data that follows a fixed, simple format."

@roborev-ci
Copy link
Copy Markdown

roborev-ci bot commented Mar 24, 2026

roborev: Combined Review (3b7d7c7)

Verdict: The changes successfully parse Claude command XML for transcripts, but require fixes for BOM handling and XML regex edge cases to prevent raw XML leaks.

Medium Severity

  • Location: internal/parser/claude.go:876

    • Problem: extractCommandText() and isCommandEnvelope() check strings.TrimSpace(content) directly, but unlike the old system-message path they do not strip a UTF-8 BOM first. If a session file starts with a BOM and the first user message is a slash
      -command envelope, the new code will neither normalize nor skip it. Because <command-message>/<command-name> were also removed from isClaudeSystemMessage(), that case now surfaces raw XML in the transcript and can corrupt FirstMessage.
    • Fix: Normalize with trimB OM() before the prefix/strip checks in both helpers, and add a test for a BOM-prefixed command envelope.
  • Location: internal/parser/claude.go lines 20-23

    • Problem: The XML regexes use [^<]* to
      capture element contents. If a skill argument contains a literal < character (e.g., HTML snippets or inequality operators), the regex fails to match. This causes the parsing to fail and the command envelope to leak into the transcript as raw XML.
    • Fix: Use the (?s) flag and
      lazy matching (.*?) instead of [^<]* (e.g., regexp.MustCompile("(?s)<command-args>(.*?)</command-args>")).

Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

…anscript

User messages containing <command-message>/<command-name> XML tags
(skill invocations like /roborev-fix 450) were incorrectly filtered
out by isClaudeSystemMessage. Instead of discarding these messages,
extract the command name and arguments into readable text
(e.g. "/roborev-fix 450") and display them as normal user messages.

The extraction only matches messages whose entire content is the
command XML envelope (no trailing prose), preventing false positives
on user messages that merely mention these tags. Bare
<command-message>-only entries are handled via fallback. Unrecognized
command envelopes are skipped rather than leaking raw XML.

Also strips UTF-8 BOM in extractCommandText and isCommandEnvelope
consistent with isClaudeSystemMessage, and removes the matching
frontend filter in MessageList.svelte.

Bumps dataVersion to 5 so existing databases automatically resync.

Fixes wesm#206

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@tlmaloney tlmaloney force-pushed the fix/skill-invocation-messages branch from 3b7d7c7 to 2634b4e Compare March 24, 2026 13:20
@roborev-ci
Copy link
Copy Markdown

roborev-ci bot commented Mar 24, 2026

roborev: Combined Review (2634b4e)

Summary Verdict: One medium severity issue found regarding fragile regex parsing of XML command envelopes.

Medium

  • Location: internal/parser/claude.go (Lines 20-24)
  • Problem:
    The regular expressions use [^<]* or [^<]+ to capture tag contents. If a command argument contains a literal < character (e.g., an unescaped input like /cmd <foo>), the regex will fail to capture the full content. This causes the parser to fail and leak
    the raw XML envelope into the transcript. Additionally, xmlCmdStripRe uses independent non-capturing groups (?:name|message|args) for both the start and end tags, meaning it will incorrectly match and strip mismatched tags (e.g., <command-name>foo</command-args> ).
  • Fix: Use (?s)(.*?) to safely match multi-line contents containing any characters, and separate the tag options in the strip regex to enforce matching start/end pairs. Example:
    xmlCmdNameRe  = regexp.MustCompile(`(?s)<command-name

(.?)) // ... update MsgRe and ArgsRe similarly xmlCmdStripRe = regexp.MustCompile((?s).?|.?|.?</command-
args>`)


---
*Synthesized from 3 reviews (agents: codex, gemini | types: default, security)*

@wesm
Copy link
Copy Markdown
Owner

wesm commented Mar 24, 2026

looks good, thanks!

@wesm wesm merged commit 01859d6 into wesm:main Mar 24, 2026
7 checks passed
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.

User messages starting with a skill invocation aren't shown in transcript

2 participants