slackapi / slackapi/slack-skills-plugin
slack_send_message_draft deletes text between `<` and a later `>`; `<` becomes a literal `<`
Nobody has claimed this yet.
- 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:
- A line containing
<followed by a later>loses the span between them. No error, no warning. </>are re-encoded as literal</>, so HTML-escaping is not a workaround.- 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
- Call
slack_send_message_draftwith the payload below. - Send the draft from the Slack client.
- Read the message back with
conversations.history(orslack_read_channel). - Call
slack_send_messagewith 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 < b and c > 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 < so it survives mrkdwn parsing, leaves an existing < 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 < b and c > d a < b and c > 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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