Skip to content

feat(message): Slack-native drafts — message drafts list/create/update/delete#112

Closed
mikaelq wants to merge 1 commit into
stablyai:mainfrom
mikaelq:feat/native-drafts
Closed

feat(message): Slack-native drafts — message drafts list/create/update/delete#112
mikaelq wants to merge 1 commit into
stablyai:mainfrom
mikaelq:feat/native-drafts

Conversation

@mikaelq

@mikaelq mikaelq commented Jul 9, 2026

Copy link
Copy Markdown

Implements #83 (option 1: separate plural drafts subcommand, keeping the existing message draft browser editor unchanged).

What

New message drafts subcommand group backed by Slack's undocumented drafts.* session endpoints (the same API the official clients use), so agents can read and write drafts that show up natively in the user's Slack client:

agent-slack message drafts list [--limit <n>] [--all]
agent-slack message drafts create <target> <text> [--thread-ts <ts>] [--broadcast]
agent-slack message drafts update <draft-id> <text> [--channel <target>] [--thread-ts <ts>] [--broadcast] [--last-updated-ts <ts>]
agent-slack message drafts delete <draft-id> [--last-updated-ts <ts>]
  • create accepts the usual targets: #channel/name, channel id, user id (opens a DM), or a message URL (drafts a thread reply, same semantics as message send).
  • Draft text goes through the existing mrkdwn → rich_text conversion (textToRichTextBlocks), so lists/bold/code/mentions render natively.
  • update replaces the body but preserves the draft's destination and attached files unless overridden; the conflict-detection client_last_updated_ts is auto-fetched for update/delete when omitted (including Slack's 7-digit fractional-padding quirk).
  • list resolves channel/DM display names best-effort.
  • Requires browser-style auth (xoxc/xoxd), like the other session-endpoint features (later, unreads); noted in the docs.

Structure

Follows the message scheduled pattern: src/slack/drafts.ts (API layer) + src/cli/message-drafts-actions.ts / message-drafts-command.ts (CLI layer). Docs updated in README, skills/agent-slack/SKILL.md, and references/commands.md.

Testing

  • 16 unit tests in test/drafts.test.ts (wire payloads, ts padding, parsing, auto-fetch/error paths); full suite, typecheck, lint, and format all pass.
  • Verified live against a real workspace: create → appears in the Slack client's Drafts → list (with resolved names) → update → delete, including thread-reply drafts via message-URL targets.

Closes #83

🤖 Generated with Claude Code

Add 'message drafts <list|create|update|delete>' backed by Slack's
undocumented drafts.* session endpoints, so agents can read and write
drafts that show up natively in the user's Slack client. The existing
'message draft' browser editor is unchanged.

References stablyai#83

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
nwparker added a commit that referenced this pull request Jul 18, 2026
Rename the browser-editor command `message draft` → `message compose`, and
add Slack-native drafts under `message draft <list|create|update|delete>`,
backed by Slack's undocumented drafts.* session endpoints so drafts show up
natively in the user's Slack client.

Takes the "compose" direction (option 2 from #83) so the two concepts get
distinct names instead of the near-homograph draft/drafts pair. Reuses the
drafts.* API layer from #112 (originally by @mikaelq).

Hardening in the update path:
- refuses drafts it can't faithfully round-trip (scheduled or multi-
  destination) instead of silently dropping the schedule/recipients;
- broadcast is inherited only when the destination is unchanged, so
  re-addressing never ratchets a reply into a new channel; adds
  `--no-broadcast` to clear an inherited flag;
- rejects `--broadcast` for DM targets, matching `message send`;
- `findDraft` prefers a well-formed record if the list response has a
  malformed duplicate.

BREAKING CHANGE: `message draft <target> [text]` no longer opens the editor;
use `message compose`. Old usage errors cleanly; `message draft --help`
points to compose. No backwards-compat shim.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: GPT-5.6-Sol <noreply@openai.com>
nwparker added a commit that referenced this pull request Jul 18, 2026
Rename the browser-editor command `message draft` → `message compose`, and
add Slack-native drafts under `message draft <list|create|update|delete>`,
backed by Slack's undocumented drafts.* session endpoints so drafts show up
natively in the user's Slack client.

Takes the "compose" direction (option 2 from #83) so the two concepts get
distinct names instead of the near-homograph draft/drafts pair. Reuses the
drafts.* API layer from #112 (originally by @mikaelq).

Hardening in the update path:
- refuses drafts it can't faithfully round-trip (scheduled or multi-
  destination) instead of silently dropping the schedule/recipients;
- broadcast is inherited only when the destination is unchanged, so
  re-addressing never ratchets a reply into a new channel; adds
  `--no-broadcast` to clear an inherited flag;
- rejects `--broadcast` for DM targets, matching `message send`;
- `findDraft` prefers a well-formed record if the list response has a
  malformed duplicate.

BREAKING CHANGE: `message draft <target> [text]` no longer opens the editor;
use `message compose`. Old usage errors cleanly; `message draft --help`
points to compose. No backwards-compat shim.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: GPT-5.6-Sol <noreply@openai.com>
nwparker added a commit that referenced this pull request Jul 18, 2026
Rename the browser-editor command `message draft` → `message compose`, and
add Slack-native drafts under `message draft <list|create|update|delete>`,
backed by Slack's undocumented drafts.* session endpoints so drafts show up
natively in the user's Slack client.

Takes the "compose" direction (option 2 from #83) so the two concepts get
distinct names instead of the near-homograph draft/drafts pair. Reuses the
drafts.* API layer from #112 (originally by @mikaelq).

Hardening in the update path:
- refuses drafts it can't faithfully round-trip (scheduled or multi-
  destination) instead of silently dropping the schedule/recipients;
- broadcast is inherited only when the destination is unchanged, so
  re-addressing never ratchets a reply into a new channel; adds
  `--no-broadcast` to clear an inherited flag;
- rejects `--broadcast` for DM targets, matching `message send`;
- `findDraft` prefers a well-formed record if the list response has a
  malformed duplicate.

BREAKING CHANGE: `message draft <target> [text]` no longer opens the editor;
use `message compose`. Old usage errors cleanly; `message draft --help`
points to compose. No backwards-compat shim.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: GPT-5.6-Sol <noreply@openai.com>
nwparker added a commit that referenced this pull request Jul 18, 2026
Rename the browser-editor command `message draft` → `message compose`, and
add Slack-native drafts under `message draft <list|create|update|delete>`,
backed by Slack's undocumented drafts.* session endpoints so drafts show up
natively in the user's Slack client.

Takes the "compose" direction (option 2 from #83) so the two concepts get
distinct names instead of the near-homograph draft/drafts pair. Reuses the
drafts.* API layer from #112 (originally by @mikaelq).

Hardening in the update path:
- refuses drafts it can't faithfully round-trip (scheduled or multi-
  destination) instead of silently dropping the schedule/recipients;
- broadcast is inherited only when the destination is unchanged, so
  re-addressing never ratchets a reply into a new channel; adds
  `--no-broadcast` to clear an inherited flag;
- rejects `--broadcast` for DM targets, matching `message send`;
- `findDraft` prefers a well-formed record if the list response has a
  malformed duplicate.

BREAKING CHANGE: `message draft <target> [text]` no longer opens the editor;
use `message compose`. Old usage errors cleanly; `message draft --help`
points to compose. No backwards-compat shim.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: GPT-5.6-Sol <noreply@openai.com>
@nwparker

Copy link
Copy Markdown
Contributor

Superseded by #119 (now merged), which implements #83 via the "compose" direction: message draft (browser editor) → message compose, and Slack-native drafts under message draft <list|create|update|delete>.

It reuses your drafts.* API layer (src/slack/drafts.ts) and its tests largely as-is — thank you for that work, @mikaelq; you're credited in the PR. Closing this as superseded.

@nwparker nwparker closed this Jul 18, 2026
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.

Proposal: integrate Slack's native drafts API

2 participants