# Slack Desk > The message you are about to post to Slack — reviewed, rewritten in Slack-native mrkdwn, > turned into a validated Block Kit payload, and shipped as the Bolt code that posts it. URL: https://slack-desk.skillsafe.ai/ API: https://slack-desk.skillsafe.ai/api.html Tokens: https://slack-desk.skillsafe.ai/tokens.html (noindex, not in the sitemap) ## The work object One artifact, four lanes: a Slack message. It arrives either as message text or as a Block Kit payload, and every lane takes the same paste. ## What runs free, in the browser, with no account 1. **An mrkdwn linter.** Slack's mrkdwn is not Markdown, and the difference is only visible after you post. The linter finds, with line numbers and the exact replacement: - `**bold**` (Slack: `*bold*`), `__italic__` (Slack: `_italic_`), `~~strike~~` (Slack: `~strike~`) - `[label](url)` (Slack: ``), `![alt](url)` (Slack: an image block) - `# headings`, `| tables |`, `---` rules, `- ` and `* ` bullets — none of which mrkdwn has - unclosed triple-backtick fences - bare `@here` / `@channel` / `@everyone` (Slack: `` etc. — a bare one notifies nobody) - bare `@username` (Slack resolves member IDs: `<@U01234567>`) and bare `#channel` - emoji shortcodes containing capitals - links with an empty label or no scheme - the three characters Slack expects escaped: `&`, `<`, `>` - text too long for one section block (3 000) or for the API (40 000) Code spans and fenced blocks are masked first, so a Markdown example inside a code block is not reported as a defect. 2. **A Block Kit validator.** Parses the payload with a real JSON parser, then checks every block against its type and the published limits, reporting the JSON path of each problem: 50 blocks per message; section text 3 000; section `fields` 10, each 2 000; header `plain_text` only, 150; context elements 10; actions elements 25; button label `plain_text`, 75; button `style` only `primary` or `danger`; `url` 3 000; `alt_text` required on every image; `block_id` and `action_id` unique; `input` blocks flagged as modal-only. 3. **A preview.** The message rendered the way Slack renders it, and the payload rendered block by block, so a literal asterisk is visible as a literal asterisk. 4. **Mechanical fixes**, applied on request: the rules whose fix is a literal substitution. The next scan is scored against the one before it — "blockers 5 -> 0, warnings 3 -> 2; still firing: SL-MENTION" — so it is visible when the message is actually clean. 5. **A re-check of the model's own answer.** Any lane's output can be pulled back into the input and re-scanned for free, and the corrected message the model returns is put through the same linter before it is shown, with the verdict above the preview. ## The four lanes (metered, model: gpt-terra) Send `task` on every request. It selects the lane and changes both the cost and the output shape. | task | stage | in | out | | --- | --- | --- | --- | | `review` | inspect | a message or a payload | LANE, SUMMARY, VERDICT, FINDINGS, REWRITE, CHECKS | | `compose` | produce | raw notes or a draft | LANE, SUMMARY, MESSAGE, SHORT, THREAD, WHY, CHECKS | | `blocks` | produce | the message | LANE, SUMMARY, PAYLOAD, FALLBACK, WHY, CHECKS | | `ship` | deliver | the payload | LANE, SUMMARY, PAYLOAD, PYTHON, JAVASCRIPT, WEBHOOK, HANDLER, CHECKS | `VERDICT` is one of `post-it`, `fix-first`, `rewrite`. The pipeline runs left to right and the handoff is a button: a review's rewrite pre-fills compose, compose's message pre-fills blocks, and a valid payload pre-fills ship. ## Two rules this app holds itself to - **The payload is parsed before it is presented.** A `PAYLOAD` section that does not parse as JSON, or that fails the Block Kit validator, is shown with its errors and without a copy button. An artifact that would not load is never offered as if it would. - **The model's text output gets the same proof its JSON output gets.** The payload has always been re-parsed and re-validated before it was presented; the corrected message text now is too, by the same browser linter, so the one question a user cannot answer for themselves is not answered by the model on its own recognisance. - **The model is reconciled against the free scan.** The client-side findings go into the run input, and every one must be fixed or explicitly set aside by rule id in `## CHECKS`. The result panel reports which rules the output stayed silent on. ## The last mile A payload that passes the validator carries an **Open in Slack's Block Kit Builder** link, which puts the exact validated JSON into Slack's own builder through the URL fragment. It is a plain navigation — this app never calls Slack, and holds no Slack token. ## Not what it is Not a Slack client and not connected to any workspace: it never talks to Slack, holds no Slack token, and posts nothing. It works on text you paste and gives you back text, JSON and code. ## Sources Derived, with credit, from four community skills: - `@anthropics/slack-messaging` — composing well-formatted, effective Slack messages in mrkdwn - `@obra/slack-messaging` — message craft - `@claude-office-skills/slack-workflows` — notifications, standup posts and approval flows - `@sickn33/slack-bot-builder` — building Slack apps with Bolt across Python and JavaScript Slack, Block Kit and Bolt are trademarks of Slack Technologies. This is an independent tool, not affiliated with or endorsed by Slack. ## Persistence Results are written to the user's own SkillSafe account in a declared `messages` collection (`acl_read: owner`), with a localStorage mirror for instant paint. Records carry the lane, the verdict, the channel, the block count and the character count; `title`, `summary` and `channel` are vector-embedded so past messages are searchable by meaning.