claude-slack-channel-bots 0.18.0 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/agent-director.md +2 -2
- package/docs/bots.md +8 -4
- package/docs/configuration.md +1 -1
- package/docs/migration.md +2 -2
- package/docs/scheduled-prompts.md +4 -4
- package/package.json +1 -1
- package/scripts/install-check.ts +5 -5
- package/scripts/write-credentials.sh +1 -1
- package/skills/debug-slack-channel-bots/SKILL.md +327 -327
- package/skills/setup-slack-channel-bots/SKILL.md +2 -2
- package/src/ack-tracker.ts +1 -1
- package/src/ad-config-file.ts +2 -2
- package/src/ad-description-phrases.ts +24 -25
- package/src/ad-error-class.ts +28 -30
- package/src/ad-phase1-types.ts +4 -5
- package/src/ad-settings.ts +36 -37
- package/src/ad-version-gate.ts +71 -78
- package/src/agent-director-client.ts +16 -16
- package/src/agent-director-errors.ts +23 -25
- package/src/agent-director-logger.ts +3 -3
- package/src/agent-director-startup.ts +22 -24
- package/src/agent-director-template.ts +24 -22
- package/src/atomic-write.ts +5 -5
- package/src/backoff.ts +3 -3
- package/src/bot-system-prompt.ts +1 -1
- package/src/channel-delivery.ts +71 -72
- package/src/checked-kill.ts +54 -54
- package/src/clear-latch.ts +6 -6
- package/src/cli-teardown.ts +64 -75
- package/src/cli.ts +138 -149
- package/src/codex-config-keys.ts +2 -2
- package/src/config.ts +170 -179
- package/src/conflict-latch.ts +114 -119
- package/src/cron-bootstrap.ts +2 -2
- package/src/cron-dispatch.ts +7 -7
- package/src/cron-log.ts +15 -16
- package/src/cron-scheduler.ts +10 -11
- package/src/crontable.ts +4 -4
- package/src/delivery-ad-scope.ts +1 -1
- package/src/delivery-constants.ts +1 -1
- package/src/delivery-decision.ts +36 -39
- package/src/delivery-engine.ts +6 -6
- package/src/delivery-intake.ts +5 -5
- package/src/delivery-lifecycle.ts +1 -1
- package/src/delivery-notices.ts +2 -2
- package/src/delivery-policy.ts +1 -1
- package/src/delivery-queue.ts +5 -5
- package/src/delivery-receipt.ts +3 -3
- package/src/health-check.ts +68 -69
- package/src/install-check-labels.ts +2 -3
- package/src/install-check.ts +9 -11
- package/src/install-skill-pointer.ts +2 -2
- package/src/interject.ts +2 -2
- package/src/invalid-flags-hold.ts +27 -28
- package/src/json-position.ts +2 -2
- package/src/jsonl-persistence-check.ts +9 -9
- package/src/kill-failure-alert.ts +38 -38
- package/src/kill-retry.ts +30 -31
- package/src/lib.ts +1 -1
- package/src/live-row-sequence.ts +146 -150
- package/src/liveness-reading.ts +15 -15
- package/src/logging.ts +1 -1
- package/src/lost-message.ts +9 -10
- package/src/message-archive.ts +2 -2
- package/src/old-life-wait.ts +32 -33
- package/src/outage-state.ts +99 -106
- package/src/pane-read.ts +14 -15
- package/src/pending-row.ts +122 -133
- package/src/permission-click-handler.ts +33 -33
- package/src/permission-poller.ts +116 -118
- package/src/permission-trail.ts +21 -23
- package/src/persona-bringup-controller.ts +48 -48
- package/src/persona-bringup.ts +9 -10
- package/src/persona-connection-errors.ts +2 -2
- package/src/persona-connections.ts +31 -31
- package/src/persona-credentials.ts +12 -12
- package/src/persona-destination-hold.ts +22 -29
- package/src/persona-destination.ts +28 -28
- package/src/persona-diagnostics.ts +32 -34
- package/src/persona-episodes.ts +118 -126
- package/src/persona-event-router.ts +7 -8
- package/src/persona-identity.ts +20 -22
- package/src/persona-lifecycle.ts +107 -111
- package/src/persona-notifier.ts +42 -49
- package/src/persona-retry-schedule.ts +9 -9
- package/src/persona-routing.ts +42 -43
- package/src/persona-serializer.ts +4 -4
- package/src/persona-slack-clients.ts +4 -4
- package/src/persona-slack-episodes.ts +4 -4
- package/src/persona-slack-validation.ts +17 -18
- package/src/persona-start.ts +17 -18
- package/src/persona-web-api-watch.ts +2 -2
- package/src/pid.ts +1 -1
- package/src/postinstall.ts +9 -9
- package/src/registry.ts +75 -85
- package/src/reload-apply.ts +15 -15
- package/src/reload-fingerprint.ts +6 -6
- package/src/reload-plan.ts +66 -70
- package/src/reload-preview-clauses.ts +5 -5
- package/src/reload-timer.ts +3 -3
- package/src/reload.ts +115 -120
- package/src/restart.ts +290 -300
- package/src/retired-keys.ts +110 -113
- package/src/row-read-rules.ts +24 -25
- package/src/server.ts +414 -425
- package/src/session-manager.ts +1852 -1957
- package/src/shutdown-deadline.ts +1 -1
- package/src/slack-log-redaction.ts +1 -1
- package/src/slow-recovery.ts +12 -13
- package/src/startup-errors.ts +1 -1
- package/src/startup-summary-ending.ts +3 -3
- package/src/state-dir-migration.ts +16 -16
- package/src/tag-description.ts +1 -1
- package/src/tag-wrapper.ts +4 -4
- package/src/test-mcp-drop.ts +1 -1
- package/src/test-timer-overrides.ts +1 -1
- package/src/tokens.ts +1 -1
- package/src/unavailable-retry.ts +193 -210
package/docs/agent-director.md
CHANGED
|
@@ -155,13 +155,13 @@ At agent-director's defaults, `pause` sets the need: its 9 s plus 30 s is 39 s,
|
|
|
155
155
|
**The startup warning.** Once per start, right after the server reads agent-director's settings and before any persona is brought up, the server writes one line to `server.log` when the setting is at or below the need:
|
|
156
156
|
|
|
157
157
|
```text
|
|
158
|
-
[slack] agent-director settings: agent_director_call_timeout_ms is <value>, at or below its need of <need> ms (the <verb> ceiling plus the 15000 ms margin): a call can time out while its verb still acts; see the switch-over runbook in docs/migration.md, section "Switching over to agent-director Phase 1"
|
|
158
|
+
[slack] agent-director settings: agent_director_call_timeout_ms is <value>, at or below its need of <need> ms (the <verb> ceiling plus the 15000 ms margin): a call can time out while its verb still acts; see the switch-over runbook in docs/migration.md, section "Switching over to agent-director Phase 1"
|
|
159
159
|
```
|
|
160
160
|
|
|
161
161
|
`<verb>` names the row whose ceiling sets the need: its verb, or `resume/spawn-with-reuse/plain-spawn` for the launch row those three share. When `[pause] timeout_seconds` holds a value that is not used, the line is this one instead, whatever the setting is:
|
|
162
162
|
|
|
163
163
|
```text
|
|
164
|
-
[slack] agent-director settings: agent_director_call_timeout_ms is <value>; its need is unknown: [pause] timeout_seconds holds <found>, a value that is not used, so pause's wait is not counted and the need without it is <need> ms; see the switch-over runbook in docs/migration.md, section "Switching over to agent-director Phase 1"
|
|
164
|
+
[slack] agent-director settings: agent_director_call_timeout_ms is <value>; its need is unknown: [pause] timeout_seconds holds <found>, a value that is not used, so pause's wait is not counted and the need without it is <need> ms; see the switch-over runbook in docs/migration.md, section "Switching over to agent-director Phase 1"
|
|
165
165
|
```
|
|
166
166
|
|
|
167
167
|
`<found>` is the number (for example `0`) or the kind of value, never the file's text. At agent-director's defaults, the default `60000` writes no line; a setting of `54000` writes the first line, naming `pause`.
|
package/docs/bots.md
CHANGED
|
@@ -106,13 +106,17 @@ Each persona's Slack app must have **interactivity enabled** with **Socket Mode*
|
|
|
106
106
|
|
|
107
107
|
### AskUserQuestion
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
For fresh or reuse Claude launches, the agent-director template denies `AskUserQuestion` (`deny: ['AskUserQuestion']`). Bots respond to operator questions via the Slack `reply` MCP tool instead. There is no `ask-relay.sh` hook and no `/ask` HTTP endpoint.
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
Fresh or reuse Claude launches save the exact `mcp__slack-channel-router__reply` allowance in their launch arguments, so it is retained on resume. Deny rules and managed restrictions still take priority; other tool approvals follow the existing permission relay. Template refreshes preserve this reply rule for subsequent launches.
|
|
112
|
+
|
|
113
|
+
Agent-director resume does not restore the template's `AskUserQuestion` denial or memory-read allowances; only the exact reply allowance is also saved in launch arguments. Independently configured permission rules and managed restrictions still apply.
|
|
112
114
|
|
|
113
115
|
### Memory-directory reads
|
|
114
116
|
|
|
115
|
-
|
|
117
|
+
On fresh or reuse Claude launches, the template also pre-allows each persona to read its own persistent-memory directory, subject to deny rules and managed restrictions. One `Read(//<config-dir>/projects/*/memory/**)` rule is derived per distinct Claude config directory across your personas (a persona's own `claude_config_dir`, the top-level `claude_config_dir`, or the `~/.claude` default). The rules follow the applied personas: when a confirmed change alters the set of config directories, the server rewrites them.
|
|
118
|
+
|
|
119
|
+
If that rewrite fails, `server.log` shows a `template refresh: … failed` line. Until the directories change again or the server restarts, a persona using a new directory may need permission to read its memory notes, depending on independently configured rules. The rule is scoped to `projects/*/memory/**` only — never the config-dir root, which holds live credentials — so it never pre-authorizes credential reads.
|
|
116
120
|
|
|
117
121
|
---
|
|
118
122
|
|
|
@@ -171,7 +175,7 @@ You received a Slack message and you haven't replied. If you meant to answer in
|
|
|
171
175
|
|
|
172
176
|
The persona can reply or end its turn. There is at most one reminder per delivered Slack message, including across server restarts. Both Claude and Codex personas are covered, regardless of `claude_config_dir`; no `jq` installation is needed.
|
|
173
177
|
|
|
174
|
-
Claude
|
|
178
|
+
Claude reminders require the `reply_tool_preallowed=1` agent-director label; conversations without it receive no new reminders. An existing label alone does not prove that the conversation's saved launch arguments include the reply allowance. Updating the template leaves existing conversations and their saved arguments unchanged; ordinary fresh or reuse launches obtain the current rule, and existing conversations continue receiving ordinary messages.
|
|
175
179
|
|
|
176
180
|
Only Slack deliveries arm reminders. Scheduled prompts, `/interject` messages and reminders themselves do not. A `reply` call by that persona suppresses the reminder even if posting fails or the call targets another conversation. Replies through another tool or service can therefore be followed by one harmless reminder.
|
|
177
181
|
|
package/docs/configuration.md
CHANGED
|
@@ -113,7 +113,7 @@ The key is used for:
|
|
|
113
113
|
|
|
114
114
|
**No persona's key may start with another persona's key.** The server rejects such a pair when it checks the configuration (see [Load-time rules](#load-time-rules)), with an error that names both personas and suggests a new name. tmux matches a session target by prefix unless it is written with `=`, so a human's tmux command without `=` for one persona (for example `tmux attach -t slack_bot_dev`) could reach another persona's session. With personas `dev` and `dev_2`, that command could reach `slack_bot_dev_2`.
|
|
115
115
|
|
|
116
|
-
Give the shorter name a suffix, such as `dev_main` beside `dev_2`, or `
|
|
116
|
+
Give the shorter name a suffix, such as `dev_main` beside `dev_2`, or `team_main` beside `team_admin`, or rename either so that neither key starts with the other. Keys that only share a start, such as `dev_a` and `dev_b`, are fine. A name that isn't its own key counts by its key: `"Dev Bot"` (key `dev_bot_…`) can't sit beside `dev` either.
|
|
117
117
|
|
|
118
118
|
Renaming a persona changes its key, so the old persona is removed and a new one added (see [What a confirmation applies](reload.md#what-a-confirmation-applies)).
|
|
119
119
|
|
package/docs/migration.md
CHANGED
|
@@ -280,7 +280,7 @@ After upgrading, every bot starts one fresh conversation; memory files are kept.
|
|
|
280
280
|
This major version accepts only the persona configuration format. These are the configuration steps of an upgrade from an earlier major version. Do them inside the switch-over runbook, not on their own: steps 1, 2, 3, 5 and 6 (the persona file, names, reply settings, Slack apps and who can reach each persona) at [step 1 of the switch-over](#step-1-check-the-host-and-stage-the-release), and steps 4, 7 and 8 (credentials files, crontable and `/interject` callers) at [step 7 of the switch-over](#step-7-install-the-new-cscb-without-starting-it). At switch-over step 1, these steps are written into the separate staged file, not `config.json`; step 7 puts that file in place as `config.json`. Until the new CSCB's first start, the new CLI keeps using the old state directory, `~/.claude/channels/slack`, so the persona `config.json`, the credentials files and the crontable go there; the first start moves that directory to `~/.config/claude-slack-channel-bots`.
|
|
281
281
|
|
|
282
282
|
1. **Rewrite `config.json` by hand.** A configuration from an earlier major version stops the server at start, with an error that names the offending setting and says the configuration must be converted to personas. Nothing is converted automatically and the file is not changed. Write a `personas` list as described in [Personas (config.json)](configuration.md#personas-configjson); the server-wide settings keep their names. The `debug-slack-channel-bots` skill covers this error under "Pre-persona configuration".
|
|
283
|
-
2. **Pick persona names whose keys don't start with one another.** The configuration check rejects such a pair. If your bots were named `
|
|
283
|
+
2. **Pick persona names whose keys don't start with one another.** The configuration check rejects such a pair. If your bots were named `team`, `team_admin`, …, don't name a persona `team` beside `team_admin`: give the shorter name a suffix, such as `team_main` (see [Persona name and key](configuration.md#persona-name-and-key)).
|
|
284
284
|
3. **Set the reply settings in `config.json`.** Choose top-level `queued_ack_reaction` and `ack_reaction`, or use their defaults after checking both emoji exist in the Slack workspace; custom emoji must exist before configuration. See [Acknowledgement reactions](server-settings.md#acknowledgement-reactions). If you had changed how replies are split, set `reply_chunk_limit` and `reply_chunk_mode` there too.
|
|
285
285
|
4. **Move the tokens into credentials files.** Tokens come only from each persona's credentials file. Create one [credentials file](configuration.md#credentials-files) per persona, then remove any token environment variables you exported for the previous version.
|
|
286
286
|
5. **Give each persona its own Slack app.** Your existing app can serve one persona; create another app for each additional persona. Add the `im:write`, `channels:read` and `groups:read` bot scopes to the existing app and re-install it; the `debug-slack-channel-bots` skill has the steps under "A persona can't open a DM" and "The message archive shows channel IDs".
|
|
@@ -301,7 +301,7 @@ Earlier releases ignore this release’s queue and can resume a bot without thei
|
|
|
301
301
|
|
|
302
302
|
---
|
|
303
303
|
|
|
304
|
-
## Upgrading from pre-
|
|
304
|
+
## Upgrading from pre-v0.6 (v0.5.x → v0.6.x)
|
|
305
305
|
|
|
306
306
|
If you installed CSCB before v0.6.0 you may have legacy artifacts on disk that are no longer needed. Clean them up by hand; no install step removes them.
|
|
307
307
|
|
|
@@ -46,16 +46,16 @@ On first boot the server auto-creates the crontable with this self-documenting h
|
|
|
46
46
|
# skipped on its own; sibling lines still schedule.
|
|
47
47
|
#
|
|
48
48
|
# Example (every day at 09:00, run grooming-tick.md, target two personas):
|
|
49
|
-
# 0 9 * * *
|
|
49
|
+
# 0 9 * * * ~/prompts/grooming-tick.md planner,reviewer
|
|
50
50
|
#
|
|
51
51
|
# Example (every hour, run standup.md, no persona list — NOT delivered yet):
|
|
52
|
-
# 0 * * * *
|
|
52
|
+
# 0 * * * * ~/prompts/standup.md
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
Each schedule is one line of **exactly 5 cron fields**, then the prompt-file path, then an optional comma-separated list of personas, each written as the persona's name or its key:
|
|
56
56
|
|
|
57
57
|
```
|
|
58
|
-
0 9 * * 1
|
|
58
|
+
0 9 * * 1 ~/prompts/weekly-report.md planner,reviewer
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
Rules:
|
|
@@ -117,7 +117,7 @@ Each load of the crontable, at start and after each edit, writes one line with i
|
|
|
117
117
|
Each load also writes one `warn` line for each line with no persona list, naming its line number in the file and its prompt path:
|
|
118
118
|
|
|
119
119
|
```text
|
|
120
|
-
2026-10-09T15:12:00.002Z cscb-cron:grooming - warn line=34 prompt
|
|
120
|
+
2026-10-09T15:12:00.002Z cscb-cron:grooming - warn line=34 prompt=~/prompts/grooming.md undeliverable: this crontable line names no personas, so it will never be delivered in this version …
|
|
121
121
|
```
|
|
122
122
|
|
|
123
123
|
Add a persona list to that line. The warning comes back at every start and every edit until you do; an unchanged crontable is not reloaded, so it is not repeated each minute. To list them in the cron log at its default location:
|
package/package.json
CHANGED
package/scripts/install-check.ts
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* scripts/install-check.ts — `bun run install-check` entry point.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* standalone diagnostic command. Calls runInstallCheck once,
|
|
6
6
|
* renders the result to stdout (success) or stderr (failure), and exits
|
|
7
7
|
* with the appropriate code.
|
|
8
8
|
*
|
|
9
9
|
* Success (exit 0) prints the OK block (binary, version, the client's
|
|
10
10
|
* minimum). When the binary is below CSCB's Phase 1 floor, the result carries
|
|
11
|
-
* the Phase 1 note
|
|
11
|
+
* the Phase 1 note and the block ends with it: the server
|
|
12
12
|
* refuses to start on that binary until agent-director Phase 1 is installed,
|
|
13
13
|
* see the switch-over runbook section. A binary that meets the floor prints
|
|
14
14
|
* the block alone. The note line's label is `INSTALL_CHECK_NOTE_LABEL`.
|
|
@@ -34,8 +34,8 @@ import { renderInstallSkillInstructions } from '../src/install-skill-pointer.ts'
|
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* The label the OK block's Phase 1 note line starts with, after its indent
|
|
37
|
-
*
|
|
38
|
-
*
|
|
37
|
+
* The install skill relays the note found under this label
|
|
38
|
+
*
|
|
39
39
|
*/
|
|
40
40
|
export const INSTALL_CHECK_NOTE_LABEL = 'note:'
|
|
41
41
|
|
|
@@ -73,7 +73,7 @@ export async function main(): Promise<void> {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
let body = renderFailure(result)
|
|
76
|
-
//
|
|
76
|
+
// append the manual-skill-install block to every failure class
|
|
77
77
|
// EXCEPT ad-version-floor-unreadable (the skill can't fix a corrupt AD
|
|
78
78
|
// package; remediation is checking the agent-director npm package
|
|
79
79
|
// installed with CSCB, with the switch-over runbook section).
|