Skip to content

feat: multi-workspace Slack support#195

Merged
auroracapital merged 2 commits intomainfrom
feat/multi-workspace-slack
May 1, 2026
Merged

feat: multi-workspace Slack support#195
auroracapital merged 2 commits intomainfrom
feat/multi-workspace-slack

Conversation

@auroracapital
Copy link
Copy Markdown
Collaborator

@auroracapital auroracapital commented May 1, 2026

Summary

  • preferences.json gains slack_workspaces[] — each entry has name, token_env, kind. Skills iterate all entries and label output per workspace (Slack/lifecycle, Slack/stagery, etc.)
  • Backwards-compatible: no slack_workspaces → falls back to legacy SLACK_MCP_ENABLED=true single-workspace path. Zero behaviour change for existing installs.
  • New bin/ops-slack-workspaces helper: lists configured workspaces, resolves token env vars, smoke-tests each via auth.test. Exits non-zero on any missing/invalid token.
  • Setup wizard step 3d now loops ("Add another workspace?") and appends each workspace to the array — tokens go into named env vars and keychain, never in prefs.
  • ops-unread, ops-go, ops-inbox, ops-comms, ops-dash, ops-status all updated.

Schema

// preferences.json
{
  "slack_workspaces": [
    { "name": "lifecycle", "token_env": "SLACK_BOT_TOKEN_LIFECYCLE", "kind": "bot_token" },
    { "name": "stagery",   "token_env": "SLACK_BOT_TOKEN_STAGERY",   "kind": "user_token" }
  ]
}

Token env vars live in shell profile or Doppler — never committed.

Migration story

Existing single-workspace configs keep working unchanged. To opt into multi-workspace, run /ops:setup slack — it appends to slack_workspaces[] without touching existing entries.

MCP wrinkle

Claude Code's MCP is bound to one Slack token at startup. For the bound workspace, mcp__claude_ai_Slack__* tools are used as before. For additional workspaces, skills fall back to direct curl with the workspace's token_env value. This is documented in each SKILL.md.

Test plan

  • 0 workspaces + SLACK_MCP_ENABLED unset → ops-unread shows available: false, skills skip with one-line note
  • 0 workspaces + SLACK_MCP_ENABLED=true → legacy path, single unnamed workspace, unchanged behaviour
  • 1 workspace with valid token → ops-slack-workspaces shows , ops-go labels Slack/lifecycle
  • 2 workspaces → both appear in briefing/inbox output with separate labels
  • Missing token env var → ops-slack-workspaces shows ✗ token env not set, exits 1
  • /ops:setup slack → adds first workspace, prompts "Add another?", adds second, both persist in prefs

To add the Stagery workspace post-merge

# 1. Add token to shell profile
echo 'export SLACK_BOT_TOKEN_STAGERY="xoxb-..."' >> ~/.zshrc && source ~/.zshrc

# 2. Run setup to register it
/ops:setup slack
# → enter name: stagery
# → enter token env: SLACK_BOT_TOKEN_STAGERY
# → "Add another?" → No

# 3. Verify
bin/ops-slack-workspaces

🤖 Generated with Claude Code


Note

Medium Risk
Medium risk because it changes Slack availability/output schema in bin/ops-unread and channel detection in bin/ops-status, which downstream skills rely on; failures would primarily affect comms scanning rather than core data integrity.

Overview
Adds multi-workspace Slack support via a new preferences.json slack_workspaces[] schema (name + token env var + kind) while keeping the legacy SLACK_MCP_ENABLED=true single-workspace path as a fallback.

Updates bin/ops-unread to emit per-workspace Slack availability (resolving each token_env safely) and adjusts bin/ops-status to treat Slack as configured if any workspace entry exists. Introduces bin/ops-slack-workspaces to list/test all configured workspace tokens (table or --json, non-zero exit on missing/invalid).

Extends setup/skill docs to loop Slack setup for multiple workspaces, label results per workspace, and document MCP-bound vs direct-curl fallback behavior, and bumps the changelog to 2.0.9.

Reviewed by Cursor Bugbot for commit 9f2f95d. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • New Features

    • Multi-workspace Slack support and a new workspace validation CLI with human and JSON output
  • Documentation

    • Setup wizard updated to persist multiple Slack workspaces and append on subsequent runs
    • Guidance updated across Slack-related skills to reflect per-workspace iteration and fallback behavior
  • Improvements

    • Per-workspace labeling in results and settings now show workspace counts
    • Backward-compatible single-workspace legacy fallback preserved; validation returns non-zero on missing/invalid tokens

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 1, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Adds multi-workspace Slack support via a slack_workspaces[] array in preferences.json, a new bin/ops-slack-workspaces validator CLI, updates to status/unread tooling to iterate workspaces with per-workspace token resolution and validation, and documentation/setup changes; preserves legacy single-workspace MCP fallback.

Changes

Cohort / File(s) Summary
Changelog & Dashboard
claude-ops/CHANGELOG.md, claude-ops/skills/ops-dash/SKILL.md
Documented v2.0.9 multi-workspace Slack behavior; dashboard shows workspace count status instead of a simple boolean.
Workspace Validator CLI
claude-ops/bin/ops-slack-workspaces
New executable: reads preferences.json slack_workspaces[], resolves each token_env, calls Slack auth.test, supports human and --json output, returns non‑zero on missing/invalid tokens, falls back to legacy MCP mode when array absent.
Status & Unread Gatherer
claude-ops/bin/ops-status, claude-ops/bin/ops-unread
ops-status now accepts .slack_workspaces[0] as configured. ops-unread builds per-workspace entries with available (token present) and notes, validates token_env identifiers to avoid set -u failures, and falls back to legacy SLACK_MCP_ENABLED behavior when appropriate.
Skills: Slack workflows (Docs)
claude-ops/skills/ops-comms/SKILL.md, claude-ops/skills/ops-go/SKILL.md, claude-ops/skills/ops-inbox/SKILL.md
Docs updated to iterate available workspaces, label outputs by workspace, use MCP tools for MCP-bound tokens and direct curl fallback for others (resolving token_env with identifier validation), and define legacy-mode behavior and "no workspaces" handling.
Setup Wizard
claude-ops/skills/setup/SKILL.md
Setup now captures multiple workspaces (name + env-var identifier), persists tokens to keychain and shell profile, registers workspaces with claude mcp add, atomically appends slack_workspaces[] entries, performs per-workspace auth.test smoke checks, and retains legacy channels.slack compat.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant prefs as Preferences\n(JSON)
    participant env as Environment\nVariables
    participant script as ops-slack-workspaces\n(Script)
    participant api as Slack API\n(auth.test)

    User->>script: Run ops-slack-workspaces [--json]
    script->>prefs: Load slack_workspaces[] 
    rect rgba(200,150,100,0.5)
    loop For each workspace
        script->>env: Resolve token via token_env
        alt Token present
            script->>api: POST auth.test
            alt Valid token
                api-->>script: OK (team_id, url)
            else Invalid token
                api-->>script: Error
            end
        else Missing token
            script->>script: Mark token_missing
        end
    end
    end
    alt --json
        script-->>User: JSON array of per-workspace results
    else Default
        script-->>User: Human-readable table/status
    end
    script-->>User: Exit code (0 if all valid / legacy OK)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 I hopped through prefs to fetch each key,

names and tokens snug beneath a tree,
auth.test checked, each workspace crowned,
legacy ears still twitching on the ground,
scripts and carrots — multi‑Slack joy found!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: multi-workspace Slack support' clearly and concisely summarizes the main feature addition across the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/multi-workspace-slack

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

Adds slack_workspaces[] to preferences.json schema. ops-unread, ops-go,
ops-inbox, ops-comms now iterate ALL configured workspaces and aggregate
results with per-workspace labels (e.g. Slack/lifecycle, Slack/stagery).
Backwards-compatible: no slack_workspaces falls back to legacy
SLACK_MCP_ENABLED=true single-workspace path.

New bin/ops-slack-workspaces helper lists configured workspaces and
smoke-tests each token via auth.test. Setup wizard step 3d now persists
workspaces into the array with a loop ("add another?") and stores tokens
in named env vars — never in preferences.json.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@blocksorg blocksorg Bot force-pushed the feat/multi-workspace-slack branch from 3770121 to 496f5ac Compare May 1, 2026 16:42
Comment thread claude-ops/skills/ops-go/SKILL.md Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@claude-ops/bin/ops-slack-workspaces`:
- Around line 22-26: The current human-output branch that sets ANSI colors (the
if using [[ -t 1 && $JSON_MODE -eq 0 ]]) must detect mobile/SSH sessions and
switch to a compact plain-text mode; add a mobile detection boolean (check
$SSH_CONNECTION, $SSH_CLIENT, $SSH_TTY, $OPS_MOBILE=1, or COLUMNS<80) and when
true set ANSI vars (GREEN/RED/YELLOW/RESET) to empty and set a new flag (e.g.,
COMPACT_MOBILE=1); then update the downstream rendering code referenced around
the human-output path and the sections noted (the output logic around lines
112-167) to, when COMPACT_MOBILE=1, emit short line-based plain text (no
banners, tables, emoji/glyph columns or ANSI) instead of the wide table/banner
formatting while preserving the JSON branch ($JSON_MODE) unchanged.
- Around line 71-72: The indirect expansion using "${!token_env:-}" can trigger
a "bad substitution" if token_env contains characters invalid for shell
identifiers; before performing indirect expansion (where token_env is read to
set ws_token), validate token_env against a POSIX variable-name pattern (e.g.,
start with letter/underscore, followed by letters/digits/underscores). If
validation fails, treat it as a configuration error: log a clear message and
skip expansion or exit with non-zero status; otherwise perform the indirect
expansion. Apply this validation for the token_env use that sets ws_token and
the other identical occurrence later in the file.

In `@claude-ops/bin/ops-unread`:
- Around line 80-83: The example preferences.json uses real-looking workspace
names in the "slack_workspaces" array (the entries with "name": "lifecycle" and
"name": "stagery" and their corresponding "token_env" values); update those
example objects to use neutral placeholders (e.g., "name": "workspace_name" or
"name": "<WORKSPACE>", and token_env values like "SLACK_BOT_TOKEN_<WORKSPACE>"
or "<YOUR_TOKEN_ENV>") so no real org/project identifiers are committed, keeping
the JSON keys "slack_workspaces", "name", "token_env", and "kind" intact.
- Around line 107-110: The script currently uses indirect expansion
"${!token_env}" (resolving into ws_token) without validating token_env, which
causes "invalid variable name" under set -euo pipefail for values like
"SLACK-BOT-TOKEN"; before dereferencing token_env validate it matches a
POSIX/Bash identifier (e.g. regex ^[a-zA-Z_][a-zA-Z0-9_]*$), and if it fails do
not attempt "${!token_env}" — instead emit an error record (write an error
message to stderr / log) and leave ws_token empty or handle the error path;
update the resolution logic surrounding token_env and ws_token to perform this
check before indirect expansion.

In `@claude-ops/skills/ops-comms/SKILL.md`:
- Around line 172-175: The skill currently filters workspaces by an `available`
flag on `slack_workspaces[]`, but that array only contains persisted metadata
and not availability; instead read the derived availability from
`channels.slack.workspaces[]` (as built by claude-ops/bin/ops-unread around
lines 76–137) or resolve each workspace's `token_env` to check presence before
filtering; update the workspace iteration to use `channels.slack.workspaces[]`
(or a resolved-token check) when deciding to call
`mcp__claude_ai_Slack__slack_search_public_and_private` (or do a direct curl for
non-bound workspaces), and keep the existing fallback logic for 0 workspaces /
legacy mode using `SLACK_MCP_ENABLED`.

In `@claude-ops/skills/ops-go/SKILL.md`:
- Around line 206-213: The workflow documents use the MCP tool
mcp__claude_ai_Slack__slack_search_public_and_private but the skill's
allowed-tools list doesn't expose any Slack tools, so /ops:go cannot run the
multi-workspace scan; update the SKILL.md allowed-tools section to include the
Slack MCP entries (e.g., mcp__claude_ai_Slack__slack_search_public_and_private
and any related mcp__claude_ai_Slack__* methods used by the flow) or explicitly
delegate Slack scanning to an existing skill that already lists those Slack
tools—ensure the allowed-tools list and any tool capability descriptions
reference the exact MCP symbols named in the workflow so the runtime can invoke
them.

In `@claude-ops/skills/ops-inbox/SKILL.md`:
- Around line 259-263: The Slack inbox section in SKILL.md references state and
MCP tools this skill doesn't have; change the flow to consume the pre-gathered
channels.slack object produced by bin/ops-unread (use channels.slack as the
source of truth instead of slack_workspaces[]/available/multi_workspace state)
and either add the required Slack MCP tools (mcp__claude_ai_Slack__* entries) to
this skill's allowed-tools or route Slack handling to the existing skill that
already exposes those tools; update the steps that mention
mcp__claude_ai_Slack__*, slack_workspaces[], and SLACK_MCP_ENABLED to instead
describe reading channels.slack and delegating to the tool-equipped skill or
include instructions to add the MCP tools to allowed-tools.

In `@claude-ops/skills/setup/SKILL.md`:
- Around line 1398-1429: The setup flow currently writes slack_workspaces[] to
prefs before the required shell/profile env persistence and Claude MCP
registration are completed; change the wizard in SKILL.md so that the steps run
non-interactively from the wizard (use the Bash tool to export/persist the env
var, add the keychain entry, and perform the Claude MCP registration via the
described commands) and only append to slack_workspaces[] after those commands
return success, or alternatively delay persisting slack_workspaces[] until a
successful MCP registration completes; update references to
bin/ops-slack-workspaces, the prefs key slack_workspaces[], and the MCP
registration step so the code path enforces running the commands
programmatically (background long-running tasks with run_in_background: true)
rather than asking the user to run them manually.
- Around line 1392-1439: The persisted token shape in slack_workspaces[] must
match the auth used by the smoke test (curl with Authorization: Bearer
${TOKEN}); update the persistence logic that writes to slack_workspaces[] and
the SLACK_BOT_TOKEN_<NAME> variable so you either (A) extract and persist a
direct Web API token (xoxb/xoxp/xapp) instead of the browser xoxc token when
building the entry, or (B) persist a structured session object (e.g. store both
xoxc and xoxd as token_session:{xoxc: "...", xoxd: "..."} in slack_workspaces[])
and update the smoke-test and any curl/fallback callers to use both
Authorization: Bearer ${xoxc} and the d=${xoxd} cookie; ensure the jq append
step that writes slack_workspaces[] and the helper bin/ops-slack-workspaces
logic reflect the chosen format and the printed instructions reference the
correct env-var/name semantics (SLACK_BOT_TOKEN_<NAME> for direct tokens or a
session-specific env/key if storing pairs).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 28df6e65-190a-4c0e-9b10-9c1ca32e45d0

📥 Commits

Reviewing files that changed from the base of the PR and between 5ce749b and 496f5ac.

📒 Files selected for processing (9)
  • claude-ops/CHANGELOG.md
  • claude-ops/bin/ops-slack-workspaces
  • claude-ops/bin/ops-status
  • claude-ops/bin/ops-unread
  • claude-ops/skills/ops-comms/SKILL.md
  • claude-ops/skills/ops-dash/SKILL.md
  • claude-ops/skills/ops-go/SKILL.md
  • claude-ops/skills/ops-inbox/SKILL.md
  • claude-ops/skills/setup/SKILL.md

Comment thread claude-ops/bin/ops-slack-workspaces Outdated
Comment thread claude-ops/bin/ops-slack-workspaces Outdated
Comment thread claude-ops/bin/ops-unread Outdated
Comment thread claude-ops/bin/ops-unread Outdated
Comment thread claude-ops/skills/ops-comms/SKILL.md Outdated
Comment thread claude-ops/skills/ops-go/SKILL.md
Comment thread claude-ops/skills/ops-inbox/SKILL.md Outdated
Comment thread claude-ops/skills/setup/SKILL.md
Comment thread claude-ops/skills/setup/SKILL.md Outdated
Sentry (MEDIUM):
- ops-go SKILL.md: replace ambiguous ${TOKEN_ENV_VALUE} placeholder with
  explicit two-step env-var resolution snippet that validates token_env is
  a legal shell identifier and dereferences with ${!token_env}.

CodeRabbit (MAJOR):
- ops-unread + ops-slack-workspaces: guard ${!token_env} indirect expansion
  with [A-Za-z_][A-Za-z0-9_]* validation. Without this, a token_env value
  containing hyphens (e.g. SLACK-BOT-TOKEN-X) would crash bash under
  set -uo pipefail with 'invalid variable name', blanking the whole unread
  payload. Now emits an explicit error record per workspace and continues.
  Verified with mixed-workspace fixture.

- ops-unread: replace concrete workspace names (lifecycle, stagery) in the
  schema docstring with <workspace_a>/<workspace_b> placeholders per
  claude-ops/**/* coding guideline (no real org/project identifiers).

- ops-slack-workspaces: add IS_MOBILE detection (OPS_MOBILE=1 /
  SSH_CONNECTION / SSH_CLIENT / SSH_TTY / COLUMNS<80) and switch to
  compact line-based output without tables/banners/ANSI in mobile/SSH
  mode, per repo formatting rule. Verified in 4 modes (JSON, mobile,
  SSH, narrow terminal).

- ops-comms + ops-inbox SKILL.md: read derived channels.slack.workspaces[]
  from bin/ops-unread output (which resolves token_env and emits
  per-workspace 'available'), NOT raw preferences.json -> slack_workspaces[]
  (which has no 'available' field — only persisted metadata). Without
  this, every workspace would look unavailable and Slack scans would be
  silently skipped.

- ops-go + ops-inbox SKILL.md: add Slack MCP tools to allowed-tools
  (mcp__claude_ai_Slack__slack_search_public_and_private,
  mcp__claude_ai_Slack__slack_read_channel). Without these the workflows
  documented for /ops:go and /ops:inbox could not execute.

- setup SKILL.md (xoxc + d cookie): document that browser-session tokens
  (xoxc-*) REQUIRE the companion d=xoxd-* cookie for slack.com/api/* —
  Bearer-only requests return {ok:false,error:not_authed}. Adds a separate
  curl example that includes -b 'd=${XOXD_TOKEN}' for xoxc tokens, and a
  new kind 'xoxc_no_cookie' to mark workspaces with the bare token but no
  cookie so direct-curl scans don't silently fail.

- setup SKILL.md (delegate-to-user): the 'wire into Claude Code plugin
  settings' step previously printed instructions and asked the user to
  edit their shell profile + run claude mcp add manually. Replaced with a
  flow that performs both via the Bash tool (writes to ~/.zshrc/.bashrc
  idempotently with grep -qF guard, runs claude mcp add directly) and only
  appends to slack_workspaces[] AFTER persistence + MCP registration
  succeed (rollback on failure with [Retry]/[Skip]/[Abort] AskUserQuestion)
  so the configured-but-unusable state never persists.

All shell scripts pass bash -n syntax check; no NEW shellcheck warnings
introduced (pre-existing SC2034/SC2059/SC2086/SC2317 unchanged).
@auroracapital
Copy link
Copy Markdown
Collaborator Author

All 10 review-thread findings addressed in commit 9f2f95d. Per-finding resolution:

# Source Severity File Resolution
1 Sentry MEDIUM skills/ops-go/SKILL.md Replaced ambiguous ${TOKEN_ENV_VALUE} placeholder with explicit two-step env-var resolution snippet (validates token_env is a legal shell identifier first, then dereferences via ${!token_env}).
2 CodeRabbit MAJOR bin/ops-slack-workspaces Added IS_MOBILE detection (OPS_MOBILE=1/SSH_*/COLUMNS<80) and switched to compact line-based output without tables/banners/ANSI in mobile/SSH mode. Verified in JSON / mobile / SSH / narrow-terminal modes.
3 CodeRabbit MAJOR bin/ops-slack-workspaces Guard ${!token_env} indirect expansion with ^[A-Za-z_][A-Za-z0-9_]*$ validation; emit status: "invalid_token_env" per workspace and continue instead of crashing the script.
4 CodeRabbit MAJOR bin/ops-unread Replaced concrete workspace names (lifecycle, stagery) in the schema docstring with <workspace_a>/<workspace_b> placeholders per the claude-ops/**/* no-real-identifiers guideline.
5 CodeRabbit MAJOR bin/ops-unread Same indirect-expansion guard as #3 — without it, token_env="SLACK-BOT-TOKEN" would crash bash under set -uo pipefail and blank the entire unread payload. Verified with mixed-workspace fixture (valid + missing + invalid).
6 CodeRabbit MAJOR skills/ops-comms/SKILL.md Read derived channels.slack.workspaces[] from bin/ops-unread output (which resolves token_env and emits per-workspace available), NOT raw preferences.json -> slack_workspaces[] (which has no available field).
7 CodeRabbit MAJOR skills/ops-go/SKILL.md Added mcp__claude_ai_Slack__slack_search_public_and_private and mcp__claude_ai_Slack__slack_read_channel to allowed-tools (plus Notion tools used by the briefing).
8 CodeRabbit MAJOR skills/ops-inbox/SKILL.md Added the same Slack MCP tools to allowed-tools and switched the multi-workspace flow to read channels.slack.workspaces[] instead of raw slack_workspaces[].
9 CodeRabbit MAJOR skills/setup/SKILL.md Documented xoxc-* tokens require companion d=xoxd-* cookie; added separate curl -b 'd=...' example and new kind: "xoxc_no_cookie" to mark workspaces with the bare browser token but no cookie so direct-curl scans don't silently fail.
10 CodeRabbit MAJOR skills/setup/SKILL.md Setup wizard now performs env-var persistence (writes to shell profile via Bash with grep -qF idempotency guard) AND Claude MCP registration (claude mcp add) directly, rather than printing instructions for the user. slack_workspaces[] is only appended AFTER both succeed; on failure the entry rolls back via AskUserQuestion: [Retry]/[Skip]/[Abort].

Verification:

  • bash -n syntax check: passes on both modified scripts.
  • shellcheck: no NEW warnings introduced (pre-existing SC2034/SC2059/SC2086/SC2317 unchanged).
  • bin/ops-unread smoke fixture (valid + missing-token + invalid-identifier workspaces): all 3 cases handled cleanly without aborting.
  • bin/ops-slack-workspaces exercised in 4 modes (JSON, OPS_MOBILE=1, SSH_CONNECTION set, COLUMNS=70): each produces correct output.

@auroracapital auroracapital merged commit 92e53e5 into main May 1, 2026
9 of 10 checks passed
@auroracapital auroracapital deleted the feat/multi-workspace-slack branch May 1, 2026 19:17
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.

Reviewed by Cursor Bugbot for commit 9f2f95d. Configure here.

Comment thread claude-ops/bin/ops-unread

SLACK_WS_COUNT=0
SLACK_WS_NAMES=()
SLACK_WS_AVAILABLE=()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused arrays declared but never read or populated

Low Severity

SLACK_WS_NAMES=() and SLACK_WS_AVAILABLE=() are declared but never populated or read anywhere in the script. The implementation uses the WS_ARRAY JSON string approach instead, making these arrays dead code — likely leftovers from an earlier design iteration that was refactored out.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9f2f95d. Configure here.

"https://slack.com/api/auth.test" 2>/dev/null
}

_jq() { command -v jq >/dev/null 2>&1 && jq -r "$@" 2>/dev/null || echo ""; }
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Helper function _jq defined but never called

Low Severity

The _jq() helper function is defined but never invoked anywhere in the script. All jq usage throughout ops-slack-workspaces calls jq directly (e.g., lines 53, 76–78, 86, 96, 104–106, etc.). This is dead code that adds unnecessary clutter.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9f2f95d. Configure here.

curl -s --max-time 5 \
-H "Authorization: Bearer $token" \
"https://slack.com/api/auth.test" 2>/dev/null
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validation tool ignores kind for xoxc cookie-based tokens

Medium Severity

The _test_token function always uses Bearer-only auth, but the setup SKILL.md (same PR) documents that xoxc tokens require a companion d=xoxd-… cookie — without it, Slack returns {"ok":false,"error":"not_authed"}. The script loads ws_kind per workspace but never branches on it to adjust the auth method. Workspaces configured via the browser-extraction path (kind: "xoxc_with_cookie") will always report as invalid, producing false failures. The setup SKILL.md at line 1464 suggests this helper as the verification step, creating a confusing post-setup experience.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9f2f95d. Configure here.

auroracapital added a commit that referenced this pull request May 2, 2026
…release (#199)

The v2.0.5 → v2.0.9 patch series shipped meaningful features (multi-workspace
Slack #195, /ops:credentials audit #184, ops-ci current-state filter #196,
telegram preflight #185, userConfig schema upgrades #182). Per semver these
should have been a minor bump. This release retroactively rolls them up
into v2.1.0 with a single coherent CHANGELOG entry.

No code changes — only:
- plugin.json: 2.0.9 → 2.1.0
- CHANGELOG.md: new [2.1.0] entry consolidating Added/Fixed/Notes for the patch series
- README header + What's-new section: refer to v2.1.0
- 11 docs/*.md badges + agents-reference subtitle + migration latest-stable note: v2.0.9 → v2.1.0

Marketplace pin (.claude-plugin/marketplace.json) bumped in follow-up PR.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

1 participant