Skip to content

feat: safe mode — redirect send to draft editor, block edit/delete - #106

Merged
nwparker merged 1 commit into
stablyai:mainfrom
TheOutdoorProgrammer:feature/safe-mode
Jul 18, 2026
Merged

feat: safe mode — redirect send to draft editor, block edit/delete#106
nwparker merged 1 commit into
stablyai:mainfrom
TheOutdoorProgrammer:feature/safe-mode

Conversation

@TheOutdoorProgrammer

Copy link
Copy Markdown
Contributor

Summary

  • Adds safe mode, an enforced human-in-the-loop mode for AI agent environments, enabled via the AGENT_SLACK_SAFE_MODE env var (1/true/yes/on) or a global --safe-mode flag
  • While active, message send is redirected to the browser draft editor and message edit/message delete are blocked
  • Implements feature 1 of Feature: Safe mode (redirect send→draft) and background/detach mode for draft editor #80 (feature 2, background/detach mode for the draft editor, is not part of this PR)

Changes

Skill instructions like "always use draft, never send" are guidance an agent can ignore. Safe mode enforces the policy at the tool level so nothing posts to Slack without human review.

  1. src/cli/safe-mode.ts (new): isSafeModeEnabled() (env var + CLI flag), safeModeBlockedError(), and redirectSendToDraft(). The redirect opens the draft editor with the send text and thread context pre-filled, prints a stderr warning, and marks the JSON output with "safe_mode": true and "redirected_from": "send". Send flags the editor cannot represent (--attach, --blocks, --schedule, --schedule-in, --reply-broadcast) are rejected with an explicit error instead of being silently dropped. The CI direct-send shortcut in the draft path is also blocked, so CI=1 cannot bypass safe mode.
  2. src/cli/message-command.ts: wires the redirect into send and the blocks into edit/delete. Read operations and reactions are unchanged (reactions felt low-risk; easy to gate later if desired).
  3. src/index.ts: registers the global --safe-mode flag.
  4. test/safe-mode.test.ts (new): 22 tests covering env var parsing, flag override, unsupported-flag rejection (individually and combined), the CI guard, and the redirect payload/draft invocation via an injected draft function.
  5. Docs: README "Safe mode" section, skills/agent-slack/references/commands.md notes on send/edit/delete, and a SKILL.md mention so agents know the behavior exists.

Verified manually: env var and flag both block edit/delete (exit 1), send with unsupported flags errors, and send with plain text opens the draft editor pre-filled with the warning on stderr. Full suite passes (261 tests), typecheck clean, lint warnings unchanged from baseline.

Adds an enforced human-in-the-loop mode (AGENT_SLACK_SAFE_MODE env var or
global --safe-mode flag) for AI agent environments:

- message send is redirected to the browser draft editor with the text
  and thread context pre-filled; output includes safe_mode/redirected_from
  markers and a stderr warning. Flags the editor cannot represent
  (--attach, --blocks, --schedule, --schedule-in, --reply-broadcast) are
  rejected instead of silently dropped, and the CI direct-send shortcut
  is blocked so safe mode cannot be bypassed with CI=1.
- message edit and message delete are blocked with a clear error.
- Read operations and reactions are unchanged.

Implements feature 1 of stablyai#80.
@AmethystLiang
AmethystLiang self-requested a review June 12, 2026 07:15
@AmethystLiang

Copy link
Copy Markdown
Contributor

gonna take a look in these two days :-)

@TheOutdoorProgrammer

Copy link
Copy Markdown
Contributor Author

@AmethystLiang any thoughts?

@TheOutdoorProgrammer

Copy link
Copy Markdown
Contributor Author

@AmethystLiang just wanted to ping again. Would really love this to be built in, Im running a fork right now and would love to come back to mainline 😊

@nwparker

Copy link
Copy Markdown
Contributor

Oh interesting. Makes sense.

Jinjing has been busy, but this makes sense!

@nwparker
nwparker merged commit e0dc184 into stablyai:main Jul 18, 2026
1 check passed
nwparker added a commit that referenced this pull request Jul 18, 2026
Takeover: integrate 5 verified community PRs (#113 #110 #109 #92 #106)
@nwparker

Copy link
Copy Markdown
Contributor

Taken over, verified, and merged into main via #121 (commit 80f0e8d). Closes #80 (feature 1).

Branch takeover/pr-106. Resolved: kept both new imports; re-applied the safe-mode docs onto the restructured SKILL.md/README.md (dropped the deleted commands.md); and repointed the redirect at the renamed composeMessage (main renamed draftMessagecomposeMessage, which would otherwise have broken the redirect).

Security property preserved: redirectSendToDraft throws in CI before reaching composeMessage's direct-send shortcut, so CI=1 cannot bypass safe mode.

Verified:

  • typecheck clean · 345 tests / 0 fail (incl. your 22 safe-mode tests) · lint 0 errors · build OK
  • AGENT_SLACK_SAFE_MODE=1 message delete … → blocked (exit 1); … message send … --schedule-in 3h → unsupported-flag rejected

Your commit 7398392 is preserved. Thanks @TheOutdoorProgrammer! Closing as merged.

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.

3 participants