#12954: feat(slack): Add channel name resolution with TTL cache
channel: slack
stale
Cluster:
Slack Integration Improvements
# PR: feat(slack): Add channel name resolution with TTL cache
## Summary
Adds `SlackChannelCache` module for efficient Slack channel lookups with automatic caching.
## What
New `src/slack/channel-cache.ts` module providing:
- **In-memory cache** with 1-hour TTL for channel listings per workspace
- **Name → ID resolution** with case-insensitive matching
- **Multiple input format support:**
- Channel names: `#general`, `general`, `GENERAL`
- Slack mentions: `<#C123456|channel-name>`
- Prefixed IDs: `slack:C123456`, `channel:C123456`
- Raw IDs: `C123456`, `G789012`
- **Pagination support** for workspaces with 1000+ channels
- **Preference for non-archived** channels when duplicates exist
- **Cache statistics** for monitoring (`getStats()`)
## Why
Currently, resolving a channel name to ID requires API calls on every request. This adds:
1. **Latency** - each message send needs to resolve the target
2. **API rate limit pressure** - unnecessary `conversations.list` calls
3. **Complexity** - each caller reimplements resolution logic
With this cache:
- First call per workspace fetches and caches all channels
- Subsequent calls use cached data (1-hour TTL)
- Natural channel name usage in message tool (`target: "#general"`)
- Handles all Slack channel reference formats uniformly
## Usage Example
```typescript
import { slackChannelCache } from "./channel-cache.js";
// Resolve channel by name (case-insensitive)
const channel = await slackChannelCache.resolveChannel(token, "#general");
// { id: "C03M3H7K4R7", name: "general", archived: false, isPrivate: false }
// Or by Slack mention format
const channel2 = await slackChannelCache.resolveChannel(token, "<#C03M3H7K4R7|general>");
// Get all channels as name→info map
const channelMap = await slackChannelCache.getChannelsByName(token);
// Map { "general" => {...}, "random" => {...}, ... }
// Clear cache (e.g., after channel created/renamed)
slackChannelCache.clearCache(token);
// Monitor cache health
const stats = slackChannelCache.getStats();
// { size: 1, tokens: 1, oldestEntryAge: 300000 }
```
## Test Coverage
- **14 tests**, all passing
- Tests cover:
- Basic channel fetching
- Cache TTL behavior (no refetch within TTL)
- Pagination handling
- All input format variations
- Case-insensitive matching
- Archived channel handling
- Cache clear operations
- Statistics reporting
```
✓ src/slack/channel-cache.test.ts (14 tests) 4ms
```
## Breaking Changes
None. This is a new additive module with no changes to existing code.
## Dependencies
- Only depends on `@slack/web-api` (already a project dependency)
- Uses existing `createSlackWebClient()` from `./client.js`
## Files Changed
- `src/slack/channel-cache.ts` (new - 195 lines)
- `src/slack/channel-cache.test.ts` (new - 195 lines)
## PR Metadata
- **Title:** `feat(slack): Add channel name resolution with TTL cache`
- **Branch:** `feature/slack-channel-name-resolution`
- **Base:** `main`
- **Labels:** `enhancement`, `slack`
## Checklist
- [x] Code follows project style guidelines
- [x] Tests pass (`npm test -- channel-cache`)
- [x] All 145 Slack tests pass (`npm test -- src/slack/`)
- [x] No breaking changes
- [x] Self-contained (no fork-specific dependencies)
- [x] Documentation included in this PR description
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR introduces a new `src/slack/channel-cache.ts` singleton (`slackChannelCache`) that fetches Slack channel listings via `conversations.list`, caches them in-memory with a 1-hour TTL per account, and provides helpers to resolve a variety of channel reference formats (IDs, `#name`, `<#id|name>`, etc.). It also adds a Vitest suite covering fetching, caching, pagination, resolution, cache clearing, and stats.
The module fits alongside existing Slack helpers (e.g., `src/slack/resolve-channels.ts`) by centralizing channel listing/resolution logic and reducing repeated API calls for name→ID lookups.
<h3>Confidence Score: 3/5</h3>
- This PR is mergeable after fixing the cache keying and duplicate-name map behavior to avoid incorrect cross-token/channel resolutions.
- Core logic is straightforward and tests cover basic behaviors, but the current cache key derivation can collide across tokens and `getChannelsByName` can return the wrong channel when duplicate names exist, which would cause incorrect routing in real use.
- src/slack/channel-cache.ts
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#7592: fix(slack): prevent unbounded memory growth in channel type cache
by namratabhaumik · 2026-02-03
81.7%
#8024: fix(slack): resolve channel names via directory for cross-account m...
by emma-digital-assistant · 2026-02-03
80.7%
#12997: feat(infra): Add query caching layer with TTL and LRU eviction
by trevorgordon981 · 2026-02-10
79.9%
#8684: fix(slack): add title param and channel resolution for file upload
by shuans · 2026-02-04
79.5%
#12414: fix(slack): do not cache API failures in thread_ts resolver
by Yida-Dev · 2026-02-09
79.1%
#13889: feat: Slack channel cache, session cost alerts & checkpoint/recover...
by trevorgordon981 · 2026-02-11
78.4%
#23056: fix(slack): exclude archived channels from startup channel resolution
by dbachelder · 2026-02-21
77.6%
#11491: feat(slack): allow agents to resolve channel IDs to names and list ...
by Lukavyi · 2026-02-07
77.5%
#5312: fix(slack): skip users.list API call when all user entries are IDs
by gunpyo-park-musinsa · 2026-01-31
76.0%
#9985: feat(slack): add channel-aware context for AI Assistant threads
by natedenh · 2026-02-05
76.0%