slackapi / slackapi/slack-skills-plugin

slack_send_message_draft deletes text between `<` and a later `>`; `&lt;` becomes a literal `&#60;`

Open
#148 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area:mcp bug
Dominant language
Python
Stars
132
Forks
34
Avg merge
1d 6h
Merged PRs (30d)
16

Description

Plugin version

N/A (claude.ai Slack connector, mcp__claude_ai_Slack__)

Client

Claude Code

Client version

2.1.273

Operating System

macOS 27.0

Description

Filing here per the note on #10 and #18 that this repo is the only public Slack-maintained place for hosted-server issues. Observed through the claude.ai Slack connector rather than the plugin, but the tool surface is the same.

slack_send_message_draft converts markdown through a different path than slack_send_message, and that path is lossy around <. Three failures, the first of which is silent data loss:

  1. A line containing < followed by a later > loses the span between them. No error, no warning.
  2. &lt; / &gt; are re-encoded as literal &#60; / &#62;, so HTML-escaping is not a workaround.
  3. Indentation from a nested list leaks into the lines that follow the list.

The same payload through slack_send_message is correct in all three cases. Same workspace, same account, three minutes apart.

We hit bug 1 in production: a status update containing a Rust generic followed later by an -> arrow was posted with the twenty characters between them missing. The author had no signal anything was gone.

Steps to reproduce
  1. Call slack_send_message_draft with the payload below.
  2. Send the draft from the Slack client.
  3. Read the message back with conversations.history (or slack_read_channel).
  4. Call slack_send_message with the identical payload and read that back too.
L1 generic: Vec<String> ends here
L2 arrow: build -> deploy ok
L3 combined: Vec<String>) pair with tests -> PR 423
L4 unmatched: a < b and c > d
L5 escaped: a &lt; b and c &gt; d
L6 bullets:
- alpha
- beta
L7 nested:
- alpha
  - beta child
L8 numbered:
1. one
2. two
L9 link: [PR 423](https://example.com/org/repo/pull/423)
L10 tail marker
Expected result

The draft serializer escapes author-supplied < as &lt; so it survives mrkdwn parsing, leaves an existing &lt; alone instead of re-encoding it, and does not carry nested-list indentation onto the lines that follow. Not by routing the draft through the send path: a draft has to stay plain text to remain editable, which is the point of a draft.

Actual result
input                                         draft path                 send path (control)
--------------------------------------------  -------------------------  -------------------
Vec<String> ends here                         unchanged                  unchanged
build -> deploy ok                            unchanged                  unchanged
Vec<String>) pair with tests -> PR 423        Vec<String> PR 423         unchanged
a < b and c > d                               a <b and c> d              unchanged
a &lt; b and c &gt; d                         a &#60; b and c &#62; d    a < b and c > d
"L7 nested:" line after a 2-level list        indented 4 spaces          not indented
"L8 numbered:" line after a 2-level list      indented 8 spaces          not indented
nested bullet characters                      bullet / bullet            bullet / white bullet
bullets in the Slack client                   not a list, literal chars  a real list
[PR 423](url)                                 <url|PR 423>               <url|PR 423>
Anything else?

Same draft-vs-send divergence as #18 (newlines) and #121 (links), reached here through angle brackets. Editing the sent message in the composer loads the full body for the draft-path message but not for the send-path one, which suggests the send path emits blocks while the draft path writes plain text into the composer.

Unrelated to this report: #121 Bug 1 no longer reproduces. [label](url) converts to <url|label> on both paths now.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the payload through slack_send_message_draft and slack_send_message, then compare the two paths using conversations.history or slack_read_channel. Trace the draft serializer from the slack_send_message_draft entry point; done means angle-bracket spans are preserved, existing escapes are not re-encoded, list indentation does not leak, and the send-path control remains unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend-api-design, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
64/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.