claude-slack-channel-bots 0.18.1 → 0.18.3
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/README.md +2 -1
- package/docs/agent-director.md +2 -0
- package/docs/channel-modes.md +3 -1
- package/docs/cli.md +17 -9
- package/docs/configuration.md +6 -7
- package/docs/migration.md +1 -1
- package/docs/reload.md +2 -2
- package/docs/server-settings.md +2 -2
- package/docs/troubleshooting.md +15 -6
- package/package.json +1 -1
- package/skills/EXAMPLE_CLAUDE.md +1 -1
- package/skills/debug-slack-channel-bots/SKILL.md +256 -61
- package/skills/setup-slack-channel-bots/SKILL.md +11 -3
- package/slack-app-manifest.yml +16 -0
- package/src/agent-director-client.ts +94 -3
- package/src/agent-director-startup.ts +8 -2
- package/src/cli-teardown.ts +224 -16
- package/src/cli.ts +388 -56
- package/src/delivery-engine.ts +45 -7
- package/src/delivery-notices.ts +92 -12
- package/src/delivery-queue.ts +25 -7
- package/src/delivery-receipt.ts +61 -6
- package/src/notice-correction.ts +52 -0
- package/src/permission-poller.ts +2 -2
- package/src/persona-destination-hold.ts +20 -2
- package/src/persona-destination.ts +75 -7
- package/src/persona-diagnostics.ts +2 -1
- package/src/persona-episodes.ts +30 -4
- package/src/persona-notifier.ts +20 -1
- package/src/registry.ts +1 -1
package/README.md
CHANGED
|
@@ -102,7 +102,8 @@ Replace the channel ID and paths with your own. [Configuration](docs/configurati
|
|
|
102
102
|
| `claude-slack-channel-bots start` | Starts the server in the background. It brings up every persona's bot. |
|
|
103
103
|
| `claude-slack-channel-bots stop` | Stops the server. The bots keep running and are picked up by the next start. |
|
|
104
104
|
| `claude-slack-channel-bots stop --stop-bots` | Stops the server, then each bot, keeping its conversation for the next start. |
|
|
105
|
-
| `claude-slack-channel-bots clean_restart` | Stops the server and every bot, then starts them again. Conversations resume. |
|
|
105
|
+
| `claude-slack-channel-bots clean_restart --server` | Stops the server and every bot, then starts them again. Conversations resume. Run it from a terminal, not from a bot. |
|
|
106
|
+
| `claude-slack-channel-bots clean_restart <bot> [<bot>…]` | Restarts only the named bots; the running server relaunches them. Naming the bot you run it from takes that bot down too, and the command with it; the server relaunches it. |
|
|
106
107
|
| `claude-slack-channel-bots credentials <persona>` | Writes one persona's credentials file from your terminal. |
|
|
107
108
|
| `claude-slack-channel-bots clear-latch <persona>` | Ends one persona's hold once a human has fixed its cause. |
|
|
108
109
|
|
package/docs/agent-director.md
CHANGED
|
@@ -117,6 +117,8 @@ The server reads the table when it starts and every 120 s after that, whatever `
|
|
|
117
117
|
|
|
118
118
|
If the file can't be read or parsed, or a `[tmux]` value is one agent-director refuses (not a whole number, negative, above 2^63 − 1, or below its minimum), the server keeps the last values it accepted (the defaults, if none yet) and writes one line to `server.log`. The `debug-slack-channel-bots` skill explains that line under "agent-director's timing settings". agent-director's own answers always decide; the server's reading of the file never overrides them.
|
|
119
119
|
|
|
120
|
+
On agent-director 0.16 and 0.17.0, a bot's state can show as `needs_intelligence` (raw state `check_permission`: an unanswered prompt shows as `needs_intelligence` once `[state] needs_intelligence_timeout_seconds` passes) or `idle_screen` (raw state `working`); CSCB reads each as its raw state, so it relays the prompt and recovers the bot as usual. On other agent-director releases CSCB reads the state as given. agent-director's `[state]` timeouts need no change for CSCB.
|
|
121
|
+
|
|
120
122
|
### Sizing the agent-director call timeout
|
|
121
123
|
|
|
122
124
|
`agent_director_call_timeout_ms` (default `60000`, an integer in `[1000, 3_600_000]`; see [Server-wide settings](server-settings.md#server-wide-settings)) is how long CSCB waits on each agent-director call it makes for its personas:
|
package/docs/channel-modes.md
CHANGED
|
@@ -73,7 +73,9 @@ In fungible mode, a persona's destination is its `invited.permission_prompts`, `
|
|
|
73
73
|
- **A channel ID:** any channel; it needs no listing and no DMs. Invite the persona's app to it, or Slack refuses the posts (see "A permission prompt or notice doesn't arrive" in [Troubleshooting](troubleshooting.md#troubleshooting)). Everyone in that channel sees the prompts and notices.
|
|
74
74
|
- **`"dm"`, written or by default:** a DM from the persona's app to its `dm.contact`. It needs `dm.enabled: true` and a `dm.contact`.
|
|
75
75
|
|
|
76
|
-
Because of the loop guard, no other persona receives every message in a fungible destination channel. After a confirmed switch change,
|
|
76
|
+
Because of the loop guard, no other persona receives every message in a fungible destination channel. After a confirmed switch change, new prompts and ordinary notices, held notices included, go to the destination of the mode turned on. Prompts already posted stay where they are and stay answerable.
|
|
77
|
+
|
|
78
|
+
[Storage-warning recovery](../skills/debug-slack-channel-bots/SKILL.md#message-saved-after-retry) keeps both the edit and its one fallback correction in the warning's original channel or DM, even after the destination changes or DMs are turned off.
|
|
77
79
|
|
|
78
80
|
## Example in fungible mode
|
|
79
81
|
|
package/docs/cli.md
CHANGED
|
@@ -60,7 +60,7 @@ Plain `stop` leaves the managed bots running — they are meant to survive a ser
|
|
|
60
60
|
claude-slack-channel-bots stop --stop-bots
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
This follows `clean_restart`'s order. It runs the [precheck](#precheck-before-stopping-bots) first, and stops nothing if it fails. When it passes, the server is stopped first, so it can't relaunch a just-exited bot mid-teardown and lose that bot's `ended` row and history, then the bot teardown runs for each persona in the last-applied record (or in `config.json` when there is no record), addressing its instance as `cscb_<key>`: pause the bot, poll until it exits (or up to `exit_timeout` seconds), then force-kill on timeout. Teardown kills but never deletes each row, preserving its `session_id` so the bots can resume their conversation history on the next start. Use it when you want a clean, flushed shutdown of the bots (for example before a host reboot).
|
|
63
|
+
This follows `clean_restart --server`'s order. It runs the [precheck](#precheck-before-stopping-bots) first, and stops nothing if it fails. When it passes, the server is stopped first, so it can't relaunch a just-exited bot mid-teardown and lose that bot's `ended` row and history, then the bot teardown runs for each persona in the last-applied record (or in `config.json` when there is no record), addressing its instance as `cscb_<key>`: pause the bot, poll until it exits (or up to `exit_timeout` seconds), then force-kill on timeout. Teardown kills but never deletes each row, preserving its `session_id` so the bots can resume their conversation history on the next start. Use it when you want a clean, flushed shutdown of the bots (for example before a host reboot).
|
|
64
64
|
|
|
65
65
|
If a persona can't be stopped after a passed precheck, the command prints a line naming it, its session and why, ends with a line counting the personas it could not stop, and exits 1 rather than silently reporting a clean stop (see [What the command prints when a bot can't be stopped](#what-the-command-prints-when-a-bot-cant-be-stopped)). `stop --stop-bots` never starts the server: after a failure the server stays stopped, unlike [`clean_restart`](#when-clean_restart-cant-stop-a-bot). When every persona is stopped, one stopped with a *Process outlived kill* text included, it exits with the server stop's status.
|
|
66
66
|
|
|
@@ -70,12 +70,17 @@ A configuration that cannot be loaded, a bad record or a missing or pre-persona
|
|
|
70
70
|
|
|
71
71
|
## `claude-slack-channel-bots clean_restart`
|
|
72
72
|
|
|
73
|
-
Runs the [precheck](#precheck-before-stopping-bots), then stops the server, gracefully exits all managed Claude Code sessions, and starts the server again.
|
|
74
|
-
|
|
75
73
|
```sh
|
|
76
|
-
claude-slack-channel-bots clean_restart
|
|
74
|
+
claude-slack-channel-bots clean_restart --server
|
|
75
|
+
claude-slack-channel-bots clean_restart <bot name or key> [<bot name or key>…]
|
|
77
76
|
```
|
|
78
77
|
|
|
78
|
+
`--server` restarts the server and every bot, for example after an upgrade, and a list restarts only those bots while the server keeps running ([Restarting named bots](#restarting-named-bots)); any other arguments, none included, print `Usage: claude-slack-channel-bots clean_restart --server, or claude-slack-channel-bots clean_restart <bot name or key> [<bot name or key>…]`, stop nothing and exit 2. **Run from a bot, it ends that bot's session and itself with it:** with `--server` nothing starts the server again, so the server and every bot stay down (run it from a terminal), and with a list naming that bot the server relaunches it, but the command can't report on it.
|
|
79
|
+
|
|
80
|
+
### `clean_restart --server`
|
|
81
|
+
|
|
82
|
+
Runs the [precheck](#precheck-before-stopping-bots), then stops the server, gracefully exits all managed Claude Code sessions, and starts the server again.
|
|
83
|
+
|
|
79
84
|
For each persona in the last-applied record (or in `config.json` when there is no record), it pauses the persona's instance, `cscb_<key>`, through agent-director and waits until the instance has ended or is missing, or its row is gone. A bot that has not exited within `exit_timeout` seconds (default 120s) is force-killed. Teardown kills but never deletes each row, preserving its `session_id` so bots resume their conversation history on the next start. All personas are processed in parallel. After the server restarts, it decides for each persona whether to resume its conversation or start a fresh one.
|
|
80
85
|
|
|
81
86
|
`clean_restart` logs its progress to `STATE_DIR/clean_restart.log`. The lines that end it with an error (config load failure, agent-director initialization failure, a failed precheck, a persona it could not stop, the alert that the server was not started, start failure) are also printed to the terminal, and so is any *Process outlived kill* text from the teardown, even on a run that goes on to start the server.
|
|
@@ -90,9 +95,6 @@ Behavior by case:
|
|
|
90
95
|
- **A persona with no instance:** logs `[slack] teardownBots: no spawn row for persona "<name>" (key=<key>) — skipping` and continues. This message appears only when a persona genuinely has no instance, never when the command failed to reach agent-director.
|
|
91
96
|
- **Server already stopped:** `stop` reports `server is not running`; `start` then brings up a fresh server.
|
|
92
97
|
- **Server fails to start again:** `clean_restart` exits non-zero with `[slack] clean_restart: start failed with exit code <n>`; the reason is in `server.log`.
|
|
93
|
-
- **agent-director unreachable, or a persona's instance can't be read:** the precheck fails and nothing is stopped: the old server and every bot keep running, and `clean_restart` exits 1 (see [Precheck before stopping bots](#precheck-before-stopping-bots)).
|
|
94
|
-
- **An agent-director older than CSCB needs:** `clean_restart` runs the same version checks as the server's start, so on an agent-director below CSCB's Phase 1 floor, or below the client's own minimum, its precheck fails at the connection and nothing is stopped. Follow the docs/migration.md section "Switching over to agent-director Phase 1". To stop the bots before the switch-over, use `stop --stop-bots`, which works on any agent-director the client accepts (see [`stop`](#claude-slack-channel-bots-stop)).
|
|
95
|
-
- **agent-director fails during the teardown:** that persona can't be stopped, so the command exits 1, as below.
|
|
96
98
|
|
|
97
99
|
### What the command prints when a bot can't be stopped
|
|
98
100
|
|
|
@@ -112,7 +114,7 @@ The lines go to the terminal and `server.log`, and each failed persona gets one
|
|
|
112
114
|
|
|
113
115
|
### When `clean_restart` can't stop a bot
|
|
114
116
|
|
|
115
|
-
While agent-director answers, a bot that can't be stopped never leaves the whole fleet down. Once every persona's line is printed, `clean_restart` checks that agent-director answers (up to 3 tries, 2 s apart).
|
|
117
|
+
While agent-director answers, a bot that can't be stopped never leaves the whole fleet down. Once every persona's line is printed, `clean_restart --server` checks that agent-director answers (up to 3 tries, 2 s apart).
|
|
116
118
|
|
|
117
119
|
- **agent-director answers:** the server is started, as at any start. Every row is kept, and the new server keeps each configured persona's own instance that is still running, one the command could not stop included.
|
|
118
120
|
- **agent-director doesn't answer:** the server is not started, so nothing starts on top of bots the command could not reach. The command prints one alert naming every persona it could not stop, appends it to `server.log` and records it as one `clean-restart-not-restarted` entry in `startup-errors.log`:
|
|
@@ -125,12 +127,18 @@ While agent-director answers, a bot that can't be stopped never leaves the whole
|
|
|
125
127
|
|
|
126
128
|
Either way the last line follows, and the command exits 1. Rows are never deleted, so running `clean_restart` again once the cause is fixed is safe.
|
|
127
129
|
|
|
130
|
+
### Restarting named bots
|
|
131
|
+
|
|
132
|
+
`clean_restart <bot>…` restarts only the bots it names, by name or key in the configuration the server runs (quote a name with spaces), each once, in configuration order. It never stops the server or another bot and starts nothing: the running server relaunches each bot it stops. It needs a running server (`STATE_DIR/server.pid`) and a `session_restart_delay` other than `0` (the recorded value: after changing it from `0`, restart the server first), then runs the [precheck](#precheck-before-stopping-bots) over the named bots only; nothing is stopped until every check has passed. It then runs the bot teardown over the named bots, never killing a bot's next life, and waits for each stopped bot to read live again, up to 90 s or `session_restart_delay` plus 30 s, whichever is longer.
|
|
133
|
+
|
|
134
|
+
Each bot then gets one line, on the terminal and in `clean_restart.log`: relaunched, or not seen relaunched within the wait. It exits 0 when every named bot was seen live again, and 1 otherwise. A name matching no persona, no running server, or a `session_restart_delay` of `0` exits 1 with one line saying `nothing was stopped`; the name is never repeated. A failed precheck, or a bot that can't be stopped, prints the [same lines](#what-the-command-prints-when-a-bot-cant-be-stopped) as `--server`, but no alert, since the server keeps running. The debugging skill's ["`clean_restart <bot>…`: the named bots"](../skills/debug-slack-channel-bots/SKILL.md#clean_restart-bot-the-named-bots) has every line, its cause and its fix.
|
|
135
|
+
|
|
128
136
|
## Precheck before stopping bots
|
|
129
137
|
|
|
130
138
|
Before `stop --stop-bots` or `clean_restart` stops anything, it checks that agent-director answers and that each persona's instance can be read:
|
|
131
139
|
|
|
132
140
|
1. It connects to agent-director. `clean_restart` makes the same version checks as the server's start. `stop --stop-bots` makes no version check of its own: any agent-director the client accepts passes, including the unsupported development placeholder `0.0.0-dev`. Ordinary 0.10.0/0.11.0 releases and 0.12.0 release candidates are refused by the client before teardown.
|
|
133
|
-
2. For each persona in the last-applied record (or in `config.json` when there is no record), it reads the persona's instance, `cscb_<key>`. A persona with no instance, or whose instance has finished, is skipped. A running instance has one line of its screen read.
|
|
141
|
+
2. For each persona in the last-applied record (or in `config.json` when there is no record), or only each named bot for `clean_restart <bot>…`, it reads the persona's instance, `cscb_<key>`. A persona with no instance, or whose instance has finished, is skipped. A running instance has one line of its screen read.
|
|
134
142
|
|
|
135
143
|
A failed precheck prints one line per persona it could not check, naming its class (such as `CONFLICT`, `UNAVAILABLE` or `CONFIG`), then a closing line, and exits 1:
|
|
136
144
|
|
package/docs/configuration.md
CHANGED
|
@@ -104,12 +104,7 @@ A name of 1–40 characters, all lower-case letters, digits and `_`, is its own
|
|
|
104
104
|
|
|
105
105
|
`"Help Desk"`, for example, has the key `help_desk_95a3a6f5`. Each persona's `persona-start` line in `server.log` shows its key.
|
|
106
106
|
|
|
107
|
-
The key
|
|
108
|
-
|
|
109
|
-
- the persona's agent-director instance, `cscb_<key>`;
|
|
110
|
-
- its tmux session, `slack_bot_<key>`;
|
|
111
|
-
- the `CSCB_PERSONA` environment variable of its Claude instance;
|
|
112
|
-
- targets: [`/interject`](bots.md#interject) and the [crontable](scheduled-prompts.md#scheduled-prompts-cscb_cron) accept the persona's name or its key.
|
|
107
|
+
The key identifies the persona's agent-director instance (`cscb_<key>`), its tmux session (`slack_bot_<key>`) and the `CSCB_PERSONA` environment variable of its Claude instance. [`/interject`](bots.md#interject) and the [crontable](scheduled-prompts.md#scheduled-prompts-cscb_cron) accept the persona's name or its key.
|
|
113
108
|
|
|
114
109
|
**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
110
|
|
|
@@ -143,6 +138,10 @@ Never put a token in `config.json`, a ticket or a chat.
|
|
|
143
138
|
|
|
144
139
|
The shipped `slack-app-manifest.yml` also grants the `lists:read` and `lists:write` bot scopes, so a bot can read and write, with its own bot token, a Slack List it has been given access to, such as one list shared by all bots. CSCB itself makes no Lists call. An app created from an earlier manifest must have both scopes added and be re-installed; until then, every Lists call fails with `missing_scope`.
|
|
145
140
|
|
|
141
|
+
The `canvases:read` and `canvases:write` bot scopes let a persona read and maintain status canvases. CSCB itself makes no canvas call. An app created from an earlier manifest must have both scopes added and be re-installed; until then, calls requiring the missing scopes fail with `missing_scope`.
|
|
142
|
+
|
|
143
|
+
The `reactions:read` bot scope lets a persona read the owner's reaction answers with `reactions.get`. An app created from an earlier manifest must have this scope added and be re-installed; until then, `reactions.get` fails with `missing_scope`.
|
|
144
|
+
|
|
146
145
|
### Channel delivery
|
|
147
146
|
|
|
148
147
|
This section applies in declarative mode; for fungible mode, see [Channel delivery in fungible mode](channel-modes.md#channel-delivery-in-fungible-mode). Each channel entry's `delivery` sets which messages in that channel reach the persona:
|
|
@@ -157,7 +156,7 @@ Any number of personas may list the same channel, each with its own `delivery`.
|
|
|
157
156
|
`dm.enabled` is each persona's DMs switch. It is off (`false`) by default.
|
|
158
157
|
|
|
159
158
|
- **On:** anyone in the workspace can DM the persona's own Slack app, and that persona alone receives the DM and answers in it. The persona can also start a DM with a workspace user by passing the user's ID to `reply`, and posts there as itself.
|
|
160
|
-
- **Off:** DMs to the persona's app are not delivered
|
|
159
|
+
- **Off:** DMs to the persona's app are not delivered; the server logs one `persona-dm-dropped` line naming the persona and `dm.enabled`. The persona cannot open or read a DM, and only corrections to previously posted messages may post there. Permission prompts can still be updated, and [storage-warning recovery](../skills/debug-slack-channel-bots/SKILL.md#message-saved-after-retry) can edit its warning and post one fallback correction in the original DM.
|
|
161
160
|
- **Group DMs** (DMs with more than one person) are never delivered to any persona, whatever `dm.enabled` says.
|
|
162
161
|
|
|
163
162
|
`dm.contact` is the person who receives the persona's prompts and notices when its destination is `"dm"`: in declarative mode when `permission_prompts` is `"dm"`, and in fungible mode when `invited.permission_prompts` is `"dm"` or unset. In either mode a `"dm"` destination needs `dm.enabled: true` and a `dm.contact`. `dm.contact` gates nothing else: it doesn't limit who can DM the persona.
|
package/docs/migration.md
CHANGED
|
@@ -17,7 +17,7 @@ This release requires agent-director 0.12.0 or later. Its 0.12.0 client and the
|
|
|
17
17
|
sudo cp docs/logrotate-startup-errors.conf /etc/logrotate.d/claude-slack-channel-bots
|
|
18
18
|
```
|
|
19
19
|
A snippet installed by an earlier release names `/home/USER/.claude/channels/slack/startup-errors.log` or `/home/USER/.config/cscb/startup-errors.log`: copy the file again, or change that path to `/home/USER/.config/claude-slack-channel-bots/startup-errors.log`.
|
|
20
|
-
4. **Stop the old server before the first start after an upgrade from a release that kept its state in `~/.claude/channels/slack` or `~/.config/cscb`.** The state directory is now `~/.config/claude-slack-channel-bots` (`$XDG_CONFIG_HOME/claude-slack-channel-bots` when `XDG_CONFIG_HOME` is an absolute path). The first `start` moves `~/.config/cscb` there, then `~/.claude/channels/slack`, overwrites nothing in the new directory, and leaves each old name as a symbolic link to it. It refuses to start (exit 1, nothing moved, a `[slack] state-migrate: a server is still running on the old state directory …` line) while a server still runs on an old directory: run `claude-slack-channel-bots stop` (it finds the old directory), then `start`; `clean_restart` does both. A host that follows the switch-over runbook stops the old server in step 3 and moves the directory at the first start, in step 10; create nothing at `~/.config/claude-slack-channel-bots` before that start, or it merges the old directory into the new one instead of moving it whole. With `SLACK_STATE_DIR` set, nothing moves. What each starting point (0.13 and earlier, 0.14.0, 0.15.0) ends with is in the [CHANGELOG](../CHANGELOG.md) entry "The state directory is renamed to `~/.config/claude-slack-channel-bots`"; a conflict or a failed move is in the debug skill under [The state directory's location and its move at start](../skills/debug-slack-channel-bots/SKILL.md#the-state-directorys-location-and-its-move-at-start).
|
|
20
|
+
4. **Stop the old server before the first start after an upgrade from a release that kept its state in `~/.claude/channels/slack` or `~/.config/cscb`.** The state directory is now `~/.config/claude-slack-channel-bots` (`$XDG_CONFIG_HOME/claude-slack-channel-bots` when `XDG_CONFIG_HOME` is an absolute path). The first `start` moves `~/.config/cscb` there, then `~/.claude/channels/slack`, overwrites nothing in the new directory, and leaves each old name as a symbolic link to it. It refuses to start (exit 1, nothing moved, a `[slack] state-migrate: a server is still running on the old state directory …` line) while a server still runs on an old directory: run `claude-slack-channel-bots stop` (it finds the old directory), then `start`; `clean_restart --server` does both. A host that follows the switch-over runbook stops the old server in step 3 and moves the directory at the first start, in step 10; create nothing at `~/.config/claude-slack-channel-bots` before that start, or it merges the old directory into the new one instead of moving it whole. With `SLACK_STATE_DIR` set, nothing moves. What each starting point (0.13 and earlier, 0.14.0, 0.15.0) ends with is in the [CHANGELOG](../CHANGELOG.md) entry "The state directory is renamed to `~/.config/claude-slack-channel-bots`"; a conflict or a failed move is in the debug skill under [The state directory's location and its move at start](../skills/debug-slack-channel-bots/SKILL.md#the-state-directorys-location-and-its-move-at-start).
|
|
21
21
|
|
|
22
22
|
### Switching over to agent-director Phase 1
|
|
23
23
|
|
package/docs/reload.md
CHANGED
|
@@ -152,9 +152,9 @@ Each row is one kind of change: what happens once you confirm it, and what happe
|
|
|
152
152
|
|
|
153
153
|
## When next-launch and server-wide changes take effect
|
|
154
154
|
|
|
155
|
-
A persona's next launch happens when the bot dies (a crash or a failed health check), at
|
|
155
|
+
A persona's next launch happens when the bot dies (a crash or a failed health check), at `clean_restart --server`, or `clean_restart <bot>…` naming it, at `stop --stop-bots` then `start`, or after a host reboot. A plain `stop` and `start` reconnects to the running instance, which is not a launch. Server-wide settings take effect at the next server start, except `allow_invited_channels` and the inherited `stop_hook_bootstrap` reminder setting: both take effect when the change is confirmed, and need no `clean_restart`. The CLI takes `stop_timeout`, `exit_timeout` and `agent_director_call_timeout_ms` from the record at once; see the table.
|
|
156
156
|
|
|
157
|
-
To make them take effect sooner, wait for the `reload-applied` line, then run `claude-slack-channel-bots clean_restart
|
|
157
|
+
To make them take effect sooner, wait for the `reload-applied` line, then run `claude-slack-channel-bots clean_restart --server` from a terminal. It reads the bot list from the record before it stops the server, so if you run it earlier it can work from the old record. The server comes back on the record, and every bot is relaunched. Conversations resume, except that a changed `claude_config_dir` starts that persona fresh. For a next-launch change to some personas only, `claude-slack-channel-bots clean_restart <bot> [<bot>…]` relaunches just those bots, and the server keeps running.
|
|
158
158
|
|
|
159
159
|
## Destructive changes
|
|
160
160
|
|
package/docs/server-settings.md
CHANGED
|
@@ -10,9 +10,9 @@ These top-level fields apply to the whole server. Confirmed changes take effect
|
|
|
10
10
|
|---|---|---|---|
|
|
11
11
|
| `bind` | string | `"127.0.0.1"` | Interface the HTTP server binds to. Use `"0.0.0.0"` to expose on all interfaces. Scheduled prompts directly enter the queue and need no HTTP or loopback. [`clear-latch`](cli.md#claude-slack-channel-bots-clear-latch) still needs loopback (the default, or `0.0.0.0`). |
|
|
12
12
|
| `port` | number | `3100` | Port the HTTP server listens on. |
|
|
13
|
-
| `session_restart_delay` | number | `60` | Seconds to wait before auto-restarting a session that crashed or disappeared. Clean exits normally relaunch about 3 s after disconnect, at most once per configured delay. A Slack message triggers reconnect after an MCP disconnect. Set to `0` to disable automatic restarts and the health check's and message-triggered reconnects; messages then wait until reconnect or restart. Agent-director refusal retries still run. Must be non-negative. For recovery notices and timing, see [Troubleshooting](troubleshooting.md#troubleshooting). |
|
|
13
|
+
| `session_restart_delay` | number | `60` | Seconds to wait before auto-restarting a session that crashed or disappeared. Clean exits normally relaunch about 3 s after disconnect, at most once per configured delay. A Slack message triggers reconnect after an MCP disconnect. Set to `0` to disable automatic restarts and the health check's and message-triggered reconnects; messages then wait until reconnect or restart, and `clean_restart <bot>…` refuses to run. Agent-director refusal retries still run. Must be non-negative. For recovery notices and timing, see [Troubleshooting](troubleshooting.md#troubleshooting). |
|
|
14
14
|
| `health_check_interval` | number | `120` | Seconds between periodic liveness polls. Set to `0` to disable; the retries of a persona agent-director refused still run. Must be non-negative. |
|
|
15
|
-
| `exit_timeout` | number | `120` | Seconds to wait for a managed Claude Code session to exit gracefully during `clean_restart` or `stop --stop-bots` before force-killing it through agent-director. |
|
|
15
|
+
| `exit_timeout` | number | `120` | Seconds to wait for a managed Claude Code session to exit gracefully during `clean_restart --server` or `stop --stop-bots` before force-killing it through agent-director. `clean_restart <bot>…` doesn't use it: it never force-kills a bot whose pause succeeds. |
|
|
16
16
|
| `stop_timeout` | number | `30` | Seconds to wait for the server process to exit after `SIGTERM` before escalating to `SIGKILL`. |
|
|
17
17
|
| `mcp_config_path` | string | `~/.claude/slack-mcp.json` | Path to the MCP config file passed to Claude Code when launching managed sessions. |
|
|
18
18
|
| `append_system_prompt_file` | string | — | One shared file supplies obedience instructions for every persona: say whose instructions each bot follows here. Its text is composed with CSCB’s tag description for `--append-system-prompt-file`. Missing file silently skipped. See `skills/EXAMPLE_CLAUDE.md` for a template. |
|
package/docs/troubleshooting.md
CHANGED
|
@@ -48,7 +48,7 @@ Each Slack request attempt, an upload included, is limited to 30 s, so an upload
|
|
|
48
48
|
Each such message logs an `unclaimed-channel` line naming the channel, and in fungible mode the reason. List the channel in a persona's `channels` and confirm the change, or turn fungible mode on for a public or private channel that is not externally shared. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-messages-in-a-channel-no-persona-is-configured-into-are-not-delivered).
|
|
49
49
|
|
|
50
50
|
**Permission relay not working**
|
|
51
|
-
Turn on the persona's app's interactivity, check the bot is in `check_permission` with `agent-director list --state check_permission --label service=cscb`, and if `permission-poller:` lines warn of skipped ticks, raise `agent_director_poll_interval_ms` (it takes effect at the next server start). [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-permission-relay-not-working).
|
|
51
|
+
Turn on the persona's app's interactivity, check the bot is in `check_permission` (on agent-director 0.16 and 0.17.0 an unanswered prompt shows as `needs_intelligence` once its timeout passes) with `agent-director list --state check_permission,needs_intelligence --label service=cscb`, and if `permission-poller:` lines warn of skipped ticks, raise `agent_director_poll_interval_ms` (it takes effect at the next server start). [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-permission-relay-not-working).
|
|
52
52
|
|
|
53
53
|
**A permission prompt or notice doesn't arrive**
|
|
54
54
|
Slack refused a post to the persona's destination; a `persona-destination-failed` line names its error, and the prompts and notices are held and retried. For `missing_scope` add `im:write` and re-install the app; for `not_in_channel` invite the app to its destination channel. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-a-permission-prompt-or-notice-doesnt-arrive).
|
|
@@ -72,7 +72,7 @@ Accepted messages remain queued; a Slack message triggers the configured reconne
|
|
|
72
72
|
Each start logs one `[slack] startupSessionManager: complete — …` line counting its personas by outcome. `latched`, `retrying`, `waiting on a live-row sequence`, `held on invalid flags` and `fresh as retired keys` are not failures. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-reading-the-start-summary).
|
|
73
73
|
|
|
74
74
|
**Delivery notices or delivery diagnostic lines**
|
|
75
|
-
For *Message not saved*, check the server disk; for *Delivery stuck* or *Message not taken in*, follow the notice's remedy; for *Messages waiting*, resolve the persona's state; for *Queue record unreadable*, preserve its file and ask the senders to resend. Accepted messages stay queued in order. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-delivery-notices-or-delivery-diagnostic-lines).
|
|
75
|
+
For *Message not saved*, check the server disk; for *Delivery stuck* or *Message not taken in*, follow the notice's remedy; for *Messages waiting*, resolve the persona's state; for *Queue record unreadable*, preserve its file and ask the senders to resend. Accepted messages stay queued in order, including when [`message-partial-receipt`](../skills/debug-slack-channel-bots/SKILL.md#message-partial-receipt) reports cut-off text. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-delivery-notices-or-delivery-diagnostic-lines).
|
|
76
76
|
|
|
77
77
|
**A persona posts a *Waiting on a prompt* or *Not connected* notice**
|
|
78
78
|
The session runs but is disconnected; accepted messages are kept until it reconnects. A human attaches with `tmux attach -t =slack_bot_<key>`, deals with anything on screen and, if it stays disconnected, types `/mcp reconnect slack-channel-router`, or restarts the server. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-a-persona-posts-a-waiting-on-a-prompt-or-not-connected-notice).
|
|
@@ -111,16 +111,25 @@ A human fixes `~/.config/agent-director/config.toml` following agent-director's
|
|
|
111
111
|
agent-director returned an error the server can't classify; the server keeps retrying. A human checks the host's agent-director and the persona's lines in `server.log`; the next retry recovers the persona once agent-director answers normally. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-a-persona-posts-an-unclassified-agent-director-error-notice).
|
|
112
112
|
|
|
113
113
|
**Session stuck during clean_restart**
|
|
114
|
-
A bot that doesn't exit within `exit_timeout` is force-killed; one that still can't be stopped fails the command (see "`clean_restart` or `stop --stop-bots` exits non-zero with `could not stop`" below). Rows are never deleted, so running `clean_restart` again is safe. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-session-stuck-during-clean_restart).
|
|
114
|
+
A bot that doesn't exit within `exit_timeout` is force-killed (under `clean_restart <bot>…`, a bot whose pause succeeds is never force-killed, and only a refused pause leads to the force-kill); one that still can't be stopped fails the command (see "`clean_restart` or `stop --stop-bots` exits non-zero with `could not stop`" below). Rows are never deleted, so running `clean_restart` again is safe. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-session-stuck-during-clean_restart).
|
|
115
|
+
|
|
116
|
+
**`clean_restart` exits 2 with `Usage:`**
|
|
117
|
+
It needs `--server` (the server and every bot) or the names of the bots to restart; a bare `clean_restart` stops nothing. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-clean_restart-exits-2-with-usage).
|
|
118
|
+
|
|
119
|
+
**The server and every bot are down after `clean_restart --server` run from a bot**
|
|
120
|
+
The command ended with the bot's session before it started the server. Start it from a terminal with `claude-slack-channel-bots start`; from a bot, name only other bots. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-the-server-and-every-bot-are-down-after-clean_restart---server-run-from-a-bot).
|
|
121
|
+
|
|
122
|
+
**`clean_restart <bot>…` says a bot was `not seen relaunched`**
|
|
123
|
+
The bot was stopped, and the server relaunches it on its own schedule; its `server.log` lines say when or why not. If `session_restart_delay` was changed from `0` since the server started, the server won't relaunch it: restart the server (`clean_restart --server` from a terminal). [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-clean_restart-bot-says-a-bot-was-not-seen-relaunched).
|
|
115
124
|
|
|
116
125
|
**`clean_restart` or `stop --stop-bots` exits non-zero with `nothing was stopped`**
|
|
117
|
-
The precheck failed, so the server and every bot keep running. Fix the cause each `precheck failed for persona` line names (see [Precheck before stopping bots](cli.md#precheck-before-stopping-bots)), then run the command again. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-clean_restart-or-stop---stop-bots-exits-non-zero-with-nothing-was-stopped).
|
|
126
|
+
The precheck failed, so the server and every bot keep running. Fix the cause each `precheck failed for persona` line names (see [Precheck before stopping bots](cli.md#precheck-before-stopping-bots)), then run the command again. For `clean_restart <bot>…`, a line naming an argument, no running server or `session_restart_delay is 0` is a refusal, not a precheck failure; it says what to run instead. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-clean_restart-or-stop---stop-bots-exits-non-zero-with-nothing-was-stopped).
|
|
118
127
|
|
|
119
128
|
**`stop --stop-bots` exits non-zero with `only the server was stopped`**
|
|
120
129
|
The installed agent-director is below the client's own minimum, so only the server was stopped. Follow the docs/migration.md section "Switching over to agent-director Phase 1". [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-stop---stop-bots-exits-non-zero-with-only-the-server-was-stopped).
|
|
121
130
|
|
|
122
131
|
**`clean_restart` or `stop --stop-bots` exits non-zero with `could not stop`**
|
|
123
|
-
Each `could not stop persona` line names a persona, its session and the class of the failure. Fix the cause and run the command again; rows are never deleted. If `clean_restart` says the server was not started, start it with `claude-slack-channel-bots start` once `agent-director version` answers. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-clean_restart-or-stop---stop-bots-exits-non-zero-with-could-not-stop).
|
|
132
|
+
Each `could not stop persona` line names a persona, its session and the class of the failure. Fix the cause and run the command again; rows are never deleted. If `clean_restart --server` says the server was not started, start it with `claude-slack-channel-bots start` once `agent-director version` answers. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-clean_restart-or-stop---stop-bots-exits-non-zero-with-could-not-stop).
|
|
124
133
|
|
|
125
134
|
**Bots come back with no memory of the prior conversation after a reboot**
|
|
126
135
|
A bot starts a new conversation when its session no longer matches the applied configuration, when it was retired by a confirmed change, once after an upgrade, or after 2 resumes in a row that failed. Search `server.log` for `sweeping row`, `pre-persona row`, `replacing the row`, `not resuming; replacing its row`, `key is retired` or `not resuming its transcript again` to see which. [Full entry](../skills/debug-slack-channel-bots/SKILL.md#symptom-bots-come-back-with-no-memory-of-the-prior-conversation-after-a-reboot).
|
|
@@ -134,7 +143,7 @@ A regression in some Claude Code releases (for example v2.1.120). Set `resume_en
|
|
|
134
143
|
|
|
135
144
|
The server daemon writes runtime output to `~/.config/claude-slack-channel-bots/server.log` (and `clean_restart.log` for the `clean_restart` subcommand). Rotation is built into CSCB, so it applies on every machine with no per-host logrotate config: when the active file crosses `CSCB_LOG_MAX_BYTES` it is rolled to `server.log.1`, the previous `.1` → `.2`, and so on up to `CSCB_LOG_KEEP` generations; the oldest is discarded. Rotated generations are not compressed. See the environment variables in [Configuration](server-settings.md#environment-variables) for the size, retention, and verbosity settings that tune this behavior.
|
|
136
145
|
|
|
137
|
-
`stop --stop-bots` and `clean_restart` append their bot-teardown lines to `server.log
|
|
146
|
+
`stop --stop-bots` and `clean_restart` append their bot-teardown lines to `server.log`, while the server is stopped or, for `clean_restart <bot>…`, while it runs (see [What the command prints when a bot can't be stopped](cli.md#what-the-command-prints-when-a-bot-cant-be-stopped)); those lines take the same timestamped form and are rotated the same way.
|
|
138
147
|
|
|
139
148
|
Note this covers only `server.log` / `clean_restart.log`. `startup-errors.log` and `permission-trail.jsonl` are separate append-only files with their own retention (see below). The cron log is never rotated; `cron_log_max_bytes` caps it instead (see [The cron log](scheduled-prompts.md#the-cron-log)).
|
|
140
149
|
|
package/package.json
CHANGED
package/skills/EXAMPLE_CLAUDE.md
CHANGED
|
@@ -12,7 +12,7 @@ You are one persona: a Slack bot with its own name and avatar. People reach you
|
|
|
12
12
|
- Mention a person or another persona with `<@ID>`, using the ID from the message tag.
|
|
13
13
|
- Your persona key is in the `CSCB_PERSONA` environment variable. Use it to name yourself, for example when you schedule a prompt for yourself.
|
|
14
14
|
- A message without a `via` attribute is a scheduled prompt or an injected message. It needs no reply unless it asks for one.
|
|
15
|
-
- A Slack message's `via` attribute says how it reached you: `dm` (a direct message), `mention` (you were @mentioned), `broadcast` (`@here` or `@channel`), `receive_all_shared` (every message in a channel other personas also read in full) or `receive_all` (every message in a channel
|
|
15
|
+
- A Slack message's `via` attribute says how it reached you: `dm` (a direct message), `mention` (you were @mentioned), `broadcast` (`@here` or `@channel`), `receive_all_shared` (every message in a channel other personas also read in full) or `receive_all` (every message in a channel you, and no other persona on this server, read in full).
|
|
16
16
|
- To schedule a prompt for yourself, append one line to the crontable named by `CSCB_CRONTABLE_PATH`, for example `echo "0 9 * * 1-5 prompts/standup.md $CSCB_PERSONA" >> "$CSCB_CRONTABLE_PATH"`. Only append with `>>`: never rewrite, reorder or delete other lines, and never save the whole file from an editor.
|
|
17
17
|
|
|
18
18
|
# Role
|