claude-slack-channel-bots 0.18.0 → 0.18.2
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 +4 -2
- package/docs/bots.md +8 -4
- package/docs/channel-modes.md +3 -1
- package/docs/cli.md +17 -9
- package/docs/configuration.md +7 -8
- package/docs/migration.md +3 -3
- package/docs/reload.md +2 -2
- package/docs/scheduled-prompts.md +4 -4
- package/docs/server-settings.md +2 -2
- package/docs/troubleshooting.md +14 -5
- 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 +559 -381
- package/skills/setup-slack-channel-bots/SKILL.md +13 -5
- package/slack-app-manifest.yml +16 -0
- 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 +110 -19
- package/src/agent-director-errors.ts +23 -25
- package/src/agent-director-logger.ts +3 -3
- package/src/agent-director-startup.ts +30 -26
- 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 +281 -84
- package/src/cli.ts +522 -201
- 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 +14 -7
- package/src/delivery-intake.ts +5 -5
- package/src/delivery-lifecycle.ts +1 -1
- package/src/delivery-notices.ts +82 -6
- package/src/delivery-policy.ts +1 -1
- package/src/delivery-queue.ts +30 -12
- 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/notice-correction.ts +52 -0
- 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 +118 -120
- 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 +42 -31
- package/src/persona-destination.ts +102 -34
- package/src/persona-diagnostics.ts +32 -34
- package/src/persona-episodes.ts +148 -130
- 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 +62 -50
- 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/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:
|
|
@@ -155,13 +157,13 @@ At agent-director's defaults, `pause` sets the need: its 9 s plus 30 s is 39 s,
|
|
|
155
157
|
**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
158
|
|
|
157
159
|
```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"
|
|
160
|
+
[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
161
|
```
|
|
160
162
|
|
|
161
163
|
`<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
164
|
|
|
163
165
|
```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"
|
|
166
|
+
[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
167
|
```
|
|
166
168
|
|
|
167
169
|
`<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/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,16 +104,11 @@ 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
|
|
|
116
|
-
Give the shorter name a suffix, such as `dev_main` beside `dev_2`, or `
|
|
111
|
+
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
112
|
|
|
118
113
|
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
114
|
|
|
@@ -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
|
|
|
@@ -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
|
|
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
|
|
|
@@ -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/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).
|
|
@@ -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/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).
|