claude-slack-channel-bots 0.15.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,7 +20,7 @@ A single HTTP MCP server that runs several independent Claude Code bots, called
20
20
  bun pm -g trust claude-slack-channel-bots
21
21
  ```
22
22
 
23
- Bun blocks the lifecycle scripts of untrusted packages, so the postinstall does not run on the plain `install` above — you must trust the package for it to fire. The `-g` flag targets the global install; without it `bun pm trust` looks for a `package.json` in the current directory and errors with `No package.json was found`. (Run `bun pm -g untrusted` to confirm it is listed first.) The postinstall then creates skeleton config files in `~/.config/cscb/` (or in `SLACK_STATE_DIR` when it is set and non-empty, the same directory the server reads) and `~/.claude/slack-mcp.json`, and links the `debug-slack-channel-bots` skill into `~/.claude/skills/`. Skip this step and a later `start` fails with `missing prerequisite: config.json`.
23
+ Bun blocks the lifecycle scripts of untrusted packages, so the postinstall does not run on the plain `install` above — you must trust the package for it to fire. The `-g` flag targets the global install; without it `bun pm trust` looks for a `package.json` in the current directory and errors with `No package.json was found`. (Run `bun pm -g untrusted` to confirm it is listed first.) The postinstall then creates skeleton config files in `~/.config/claude-slack-channel-bots/` (or in `SLACK_STATE_DIR` when it is set and non-empty, the same directory the server reads) and `~/.claude/slack-mcp.json`, and links the `debug-slack-channel-bots` skill into `~/.claude/skills/`. Skip this step and a later `start` fails with `missing prerequisite: config.json`.
24
24
 
25
25
  3. **Run the setup skill:**
26
26
 
@@ -63,20 +63,20 @@ A single HTTP MCP server that runs several independent Claude Code bots, called
63
63
  | `darwin-x64` (Intel Mac) | **Not supported** by agent-director |
64
64
  | Windows | **Not supported** by agent-director |
65
65
 
66
- If the host is unsupported, the system-installed `agent-director` itself will refuse to install or run; CSCB's startup gate then exits non-zero with one of the `ad-system-install-*` class labels (see [Startup errors](docs/troubleshooting.md#startup-errors)) and writes the failure to `~/.config/cscb/startup-errors.log` and stderr. Consult [agent-director's documentation](https://github.com/gabemahoney/agent-director) for the canonical platform support list.
66
+ If the host is unsupported, the system-installed `agent-director` itself will refuse to install or run; CSCB's startup gate then exits non-zero with one of the `ad-system-install-*` class labels (see [Startup errors](docs/troubleshooting.md#startup-errors)) and writes the failure to `~/.config/claude-slack-channel-bots/startup-errors.log` and stderr. Consult [agent-director's documentation](https://github.com/gabemahoney/agent-director) for the canonical platform support list.
67
67
 
68
68
  ---
69
69
 
70
70
  ## A first configuration
71
71
 
72
- `config.json` lives in `~/.config/cscb/` (or `SLACK_STATE_DIR`). This one runs one persona, `planner`, that receives every message in one channel and posts its permission prompts there:
72
+ `config.json` lives in `~/.config/claude-slack-channel-bots/` (or `SLACK_STATE_DIR`). This one runs one persona, `planner`, that receives every message in one channel and posts its permission prompts there:
73
73
 
74
74
  ```json
75
75
  {
76
76
  "personas": [
77
77
  {
78
78
  "name": "planner",
79
- "credentials_file": "~/.config/cscb/planner-credentials.json",
79
+ "credentials_file": "~/.config/claude-slack-channel-bots/planner-credentials.json",
80
80
  "working_directory": "~/projects/alpha",
81
81
  "channels": [
82
82
  { "id": "C0123456789", "delivery": "all" }
@@ -116,7 +116,7 @@ Talk to a persona in its channels or, when its `dm.enabled` is `true`, by direct
116
116
  On a running server, saving `config.json` changes nothing yet. Within about 5 seconds the server writes a preview of the change to `config.json.pending`. Read it, then confirm it by renaming it:
117
117
 
118
118
  ```sh
119
- cd "${SLACK_STATE_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/cscb}" && mv config.json.pending config.json.apply
119
+ cd "${SLACK_STATE_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/claude-slack-channel-bots}" && mv config.json.pending config.json.apply
120
120
  ```
121
121
 
122
122
  The server applies it without a restart. Lines that start `DESTRUCTIVE:` name personas the change retires; their conversations are not resumed. [Reload](docs/reload.md) explains the preview and what each kind of change does.
@@ -31,7 +31,7 @@ Read this before turning fungible mode on. Each persona's Claude worker runs wit
31
31
  The audit lines in `server.log` are `persona-invited-channel`, logged the first time a persona hears a channel in fungible mode (naming the channel, `public` or `private`, and its channel delivery), and `persona-channel-delivery-set`, logged for each stored `set_channel_delivery` choice. The debugging skill explains both ([`persona-invited-channel`](../skills/debug-slack-channel-bots/SKILL.md#persona-invited-channel), [`persona-channel-delivery-set`](../skills/debug-slack-channel-bots/SKILL.md#persona-channel-delivery-set)). To list them:
32
32
 
33
33
  ```sh
34
- grep -E 'persona-(invited-channel|channel-delivery-set)' ~/.config/cscb/server.log*
34
+ grep -E 'persona-(invited-channel|channel-delivery-set)' ~/.config/claude-slack-channel-bots/server.log*
35
35
  ```
36
36
 
37
37
  A persona logs a channel's `persona-invited-channel` line only once until the server restarts or the persona is brought up fresh, so on a long-running server, log rotation can discard a channel's only audit line (see [Server log rotation](troubleshooting.md#server-log-rotation)). After a restart, the first event from each channel a persona hears in fungible mode logs its line again.
@@ -51,7 +51,7 @@ The switch changes through a confirmed edit, like every other setting:
51
51
  Before you turn it on, review each persona's app's channel memberships in Slack, private channels included: each one becomes a channel the persona serves. Past `unclaimed-channel` lines in `server.log` show channels whose messages reached a persona's app with no persona serving them:
52
52
 
53
53
  ```sh
54
- grep unclaimed-channel ~/.config/cscb/server.log*
54
+ grep unclaimed-channel ~/.config/claude-slack-channel-bots/server.log*
55
55
  ```
56
56
 
57
57
  **Turning it off.** The change is checked by the declarative rules, so each persona needs a valid declarative section: a persona whose `channels` or `permission_prompts` breaks a declarative-mode rule makes the change `INVALID` (see [Load-time rules](configuration.md#load-time-rules)). From the next event, each persona serves its listed channels again, each at its `delivery`. Turning it off changes no stored choice on disk: the choices stop applying, and they apply again when fungible mode is turned back on.
@@ -89,13 +89,13 @@ Invite each persona's Slack app to the channels it should serve, and `triage`'s
89
89
  "personas": [
90
90
  {
91
91
  "name": "triage",
92
- "credentials_file": "~/.config/cscb/triage-credentials.json",
92
+ "credentials_file": "~/.config/claude-slack-channel-bots/triage-credentials.json",
93
93
  "working_directory": "~/projects/triage",
94
94
  "invited": { "permission_prompts": "C0123456789" }
95
95
  },
96
96
  {
97
97
  "name": "concierge",
98
- "credentials_file": "~/.config/cscb/concierge-credentials.json",
98
+ "credentials_file": "~/.config/claude-slack-channel-bots/concierge-credentials.json",
99
99
  "working_directory": "~/projects/concierge",
100
100
  "dm": { "enabled": true, "contact": "U0123456789" }
101
101
  }
package/docs/cli.md CHANGED
@@ -27,13 +27,13 @@ The server first runs the agent-director startup gate: it imports `agent-directo
27
27
  - **The server exits during startup:** `start` exits 1. It prints why the server stopped, followed by the last lines (at most 20) the server wrote to `server.log`, which carry the server's own reason:
28
28
 
29
29
  ```
30
- [slack] Server failed to start (exit code 1). From /home/you/.config/cscb/server.log:
30
+ [slack] Server failed to start (exit code 1). From /home/you/.config/claude-slack-channel-bots/server.log:
31
31
  ```
32
32
 
33
33
  - **The server is still starting after 30 seconds:** `start` exits 0 and leaves it running.
34
34
 
35
35
  ```
36
- [slack] Server is still starting in the background (PID 12345) after 30s — its log is /home/you/.config/cscb/server.log
36
+ [slack] Server is still starting in the background (PID 12345) after 30s — its log is /home/you/.config/claude-slack-channel-bots/server.log
37
37
  ```
38
38
 
39
39
  At a start with no last-applied record, a configuration from before personas stops the start. The server writes the conversion error to `server.log` and exits, so `start` shows the same line on the terminal and exits 1. In `server.log`, where each line is prefixed with a timestamp, it reads:
@@ -194,6 +194,6 @@ It needs no agent-director, reads no configuration file and writes or removes no
194
194
 
195
195
  ## PID file
196
196
 
197
- The PID file is stored at `STATE_DIR/server.pid` (default: `~/.config/cscb/server.pid`). It is written on startup and removed on clean shutdown. A conflict check at startup prevents running two servers against the same state directory.
197
+ The PID file is stored at `STATE_DIR/server.pid` (default: `~/.config/claude-slack-channel-bots/server.pid`). It is written on startup and removed on clean shutdown. A conflict check at startup prevents running two servers against the same state directory.
198
198
 
199
199
  Beside it, `STATE_DIR/server.port` records the server's process ID and the port it actually listens on. The server writes it once it is listening and removes it on shutdown. A start that finds a stale PID file removes a stale `server.port` with it, and `stop` removes it with the PID file. [`clear-latch`](#claude-slack-channel-bots-clear-latch) reads it to find the server, and uses it only when the process ID it records is the one in `server.pid`.
@@ -4,7 +4,7 @@ The persona reference for `config.json`: every persona field, credentials files
4
4
 
5
5
  ## Personas (config.json)
6
6
 
7
- `config.json` is read from `~/.config/cscb/config.json` by default (`$XDG_CONFIG_HOME/cscb/config.json` when `XDG_CONFIG_HOME` is an absolute path). Override the directory with `SLACK_STATE_DIR`. The server needs only this file and the credentials files it names.
7
+ `config.json` is read from `~/.config/claude-slack-channel-bots/config.json` by default (`$XDG_CONFIG_HOME/claude-slack-channel-bots/config.json` when `XDG_CONFIG_HOME` is an absolute path). Override the directory with `SLACK_STATE_DIR`. The server needs only this file and the credentials files it names.
8
8
 
9
9
  Each bot is a **persona**: one Slack app, one Claude instance with its own working directory, and the channels it serves. In declarative mode, the default, those are the channels it is configured into, and its tools may target only them; in fungible mode, they are the public and private channels its app is invited to that are not externally shared, and its tools may target any channel ID: the call goes to Slack, which decides (see [Tools](bots.md#tools) and [Channel modes](channel-modes.md#channel-modes)). Create one Slack app per persona (see `slack-app-manifest.yml`); that app gives the persona its own name and avatar in Slack.
10
10
 
@@ -29,7 +29,7 @@ A complete `config.json` in declarative mode (`allow_invited_channels` absent),
29
29
  "personas": [
30
30
  {
31
31
  "name": "planner",
32
- "credentials_file": "~/.config/cscb/planner-credentials.json",
32
+ "credentials_file": "~/.config/claude-slack-channel-bots/planner-credentials.json",
33
33
  "working_directory": "~/projects/alpha",
34
34
  "channels": [
35
35
  { "id": "C0123456789", "delivery": "all" },
@@ -39,7 +39,7 @@ A complete `config.json` in declarative mode (`allow_invited_channels` absent),
39
39
  },
40
40
  {
41
41
  "name": "reviewer",
42
- "credentials_file": "~/.config/cscb/reviewer-credentials.json",
42
+ "credentials_file": "~/.config/claude-slack-channel-bots/reviewer-credentials.json",
43
43
  "working_directory": "~/projects/beta",
44
44
  "channels": [
45
45
  { "id": "C0555555555", "delivery": "mentions" }
@@ -51,7 +51,7 @@ A complete `config.json` in declarative mode (`allow_invited_channels` absent),
51
51
  },
52
52
  {
53
53
  "name": "helpdesk",
54
- "credentials_file": "~/.config/cscb/helpdesk-credentials.json",
54
+ "credentials_file": "~/.config/claude-slack-channel-bots/helpdesk-credentials.json",
55
55
  "working_directory": "~/projects/helpdesk",
56
56
  "dm": { "enabled": true, "contact": "U0987654321" },
57
57
  "permission_prompts": "dm"
package/docs/migration.md CHANGED
@@ -12,12 +12,12 @@ This release and agent-director Phase 1 are installed together, and rolled back
12
12
  * * * * * $HOME/.agent-director/bin/agent-director find-missing
13
13
  ```
14
14
  The job must run as the workers' user and resolve their tmux socket, the socket switch-over step 1 pins.
15
- 3. **Install the startup-errors logrotate snippet** so `~/.config/cscb/startup-errors.log` doesn't grow unboundedly. Edit `USER` in the file to match the OS account running CSCB:
15
+ 3. **Install the startup-errors logrotate snippet** so `~/.config/claude-slack-channel-bots/startup-errors.log` doesn't grow unboundedly. Edit `USER` in the file to match the OS account running CSCB:
16
16
  ```sh
17
17
  sudo cp docs/logrotate-startup-errors.conf /etc/logrotate.d/claude-slack-channel-bots
18
18
  ```
19
- A snippet installed by an earlier release names `/home/USER/.claude/channels/slack/startup-errors.log`: copy the file again, or change that path to `/home/USER/.config/cscb/startup-errors.log`.
20
- 4. **Stop the old server before the first start after an upgrade from a release that kept its state under `~/.claude`.** Claude Code asks the user before every write under `~/.claude`, so the state directory is now `~/.config/cscb` (`$XDG_CONFIG_HOME/cscb` when `XDG_CONFIG_HOME` is an absolute path), beside the credentials files and the crontable. The first `start` moves the old directory's files there and leaves a symbolic link at the old name; it refuses to start while a server is still running on the old directory. Run `claude-slack-channel-bots stop` (it finds the old directory), then `start`; `clean_restart` does both. Until that start, `stop`, `credentials` and the other commands keep using the old directory. 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/cscb` 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 the move does with each file, and with a file present in both places, is in the [CHANGELOG](../CHANGELOG.md) entry "The state directory moves out of `~/.claude`".
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).
21
21
 
22
22
  ### Switching over to agent-director Phase 1
23
23
 
@@ -36,7 +36,7 @@ Your new CSCB is installed and its server refused to start with `ad-below-phase1
36
36
  This block covers only a refusal before agent-director Phase 1 is installed on the host, by step 8 or otherwise. Act in this order:
37
37
 
38
38
  1. If `config.json` is in persona form and no pre-persona copy of it exists, neither step 1's copy nor one you kept elsewhere, stop here and change nothing: no reinstall, no start and no step 1. Rebuild the pre-persona `config.json` by hand, as [step 8 of "Rolling back the switch-over"](#step-8-reinstall-the-previous-cscb) says. Once you have rebuilt it, follow this block again from its start.
39
- 2. Otherwise, first rebuild by hand to their pre-persona form, as [step 8 of "Rolling back the switch-over"](#step-8-reinstall-the-previous-cscb) says, the crontable targets and `/interject` callers that the conversion to personas left in persona form where step 1's copy of them is missing. Then reinstall the previous CSCB, the version step 1 recorded or else the version the host ran before, with the pre-persona `config.json`, crontable, `/interject` callers, `access.json` and Slack token environment variables: from step 1's files, or a pre-persona copy of `config.json` you kept, where they exist, and otherwise from those still in place. Start it, re-enabling the host's autostart for CSCB if it was disabled, as step 8's "no go" branch does. Put the files back by the old state directory's name, `~/.claude/channels/slack`: a start of the new CSCB has already moved that directory to `~/.config/cscb` and left a symbolic link at the old name, which the previous CSCB reads through.
39
+ 2. Otherwise, first rebuild by hand to their pre-persona form, as [step 8 of "Rolling back the switch-over"](#step-8-reinstall-the-previous-cscb) says, the crontable targets and `/interject` callers that the conversion to personas left in persona form where step 1's copy of them is missing. Then reinstall the previous CSCB, the version step 1 recorded or else the version the host ran before, with the pre-persona `config.json`, crontable, `/interject` callers, `access.json` and Slack token environment variables: from step 1's files, or a pre-persona copy of `config.json` you kept, where they exist, and otherwise from those still in place. Start it, re-enabling the host's autostart for CSCB if it was disabled, as step 8's "no go" branch does. Put the files back by the old state directory's name, `~/.claude/channels/slack`: a start of the new CSCB has already moved that directory to `~/.config/claude-slack-channel-bots` and left a symbolic link at the old name, which the previous CSCB reads through.
40
40
  3. Then, if agent-director is not 0.10.0 (below 0.7.0 under `ad-system-install-too-old`; 0.7.0 to 0.9.x under `ad-below-phase1-floor`), bring it to 0.10.0 outside this runbook. This block gives no command for it.
41
41
  4. Then start the runbook at [step 1](#step-1-check-the-host-and-stage-the-release). Step 3 is then the old CSCB's own stop.
42
42
 
@@ -83,7 +83,7 @@ Do this beforehand, with the old CSCB running and still installed as the global
83
83
 
84
84
  `expire` is not among them: CSCB never calls it. [Sizing the agent-director call timeout](agent-director.md#sizing-the-agent-director-call-timeout) works through examples.
85
85
  8. **Leftover sessions.** As the workers' user, on the pinned socket, compare `tmux ls` with `agent-director list`, and record in the switch-over log every `slack_bot_` session that no row names.
86
- 9. **Stage the new release without installing it.** Choose its exact version, record it in the switch-over log and confirm that it is available to install. Write the persona configuration, with `agent_director_call_timeout_ms`, in a separate file, never `config.json`, which the old CSCB reads. Prepare the Slack apps. Nothing is installed over the global package yet, so step 3's `stop --stop-bots` is the old version's own and reads the old, pre-persona `config.json` from the old state directory, `~/.claude/channels/slack`, where the old package keeps it. In the staged file, name each persona's `credentials_file` in that directory too, never under `~/.config/cscb` (step 7 says why). Steps 1, 2, 3, 5 and 6 of [Upgrading to personas](#upgrading-to-personas) belong here.
86
+ 9. **Stage the new release without installing it.** Choose its exact version, record it in the switch-over log and confirm that it is available to install. Write the persona configuration, with `agent_director_call_timeout_ms`, in a separate file, never `config.json`, which the old CSCB reads. Prepare the Slack apps. Nothing is installed over the global package yet, so step 3's `stop --stop-bots` is the old version's own and reads the old, pre-persona `config.json` from the old state directory, `~/.claude/channels/slack`, where the old package keeps it. In the staged file, name each persona's `credentials_file` in that directory too, never under `~/.config/claude-slack-channel-bots` (step 7 says why). Steps 1, 2, 3, 5 and 6 of [Upgrading to personas](#upgrading-to-personas) belong here.
87
87
  10. **Copies for rollback.** Keep copies of the pre-persona `config.json`, the crontable, the `/interject` callers (the host crontab's `curl` lines included), `access.json` and the Slack token environment variables the old CSCB uses. The old CSCB keeps `config.json`, the crontable and `access.json` in the old state directory, `~/.claude/channels/slack`: keep the copies outside it, because the first start in step 10 moves that directory. Record the old CSCB's exact version in the switch-over log beside them.
88
88
  11. **The orchestrator prompt (operator action).** The shared orchestrator prompt's "ship now" wording may go out any time before the switch-over. The shared orchestrator prompt is the system prompt your orchestrator bots load, for example the file `append_system_prompt_file` names.
89
89
 
@@ -148,7 +148,7 @@ A leftover that cannot be ended this way means no Phase 1 install: take step 8's
148
148
 
149
149
  Steps 4, 7 and 8 of [Upgrading to personas](#upgrading-to-personas) belong here. From this step the new CSCB is deployed but not started.
150
150
 
151
- **Steps 7 and 8, the call-timeout edit included, must not create `~/.config/cscb`.** The credentials command makes the directory of a `credentials_file` that is missing, so a path under `~/.config/cscb` creates it. The new CSCB's first start moves the old state directory to `~/.config/cscb` in one rename when that does not exist; when it exists, the start merges the old directory into it entry by entry, and a file that differs in the two is a conflict that leaves the old directory in place.
151
+ **Steps 7 and 8, the call-timeout edit included, must not create `~/.config/claude-slack-channel-bots`.** The credentials command makes the directory of a `credentials_file` that is missing, so a path under `~/.config/claude-slack-channel-bots` creates it. The new CSCB's first start moves the old state directory to `~/.config/claude-slack-channel-bots` in one rename when that does not exist; when it exists, the start merges the old directory into it entry by entry, and a file that differs in the two is a conflict that leaves the old directory in place.
152
152
 
153
153
  #### Step 8: Install agent-director Phase 1
154
154
 
@@ -179,7 +179,7 @@ Every other agent on the host is started again by its owner (operator action), w
179
179
  ```
180
180
  The first start has no last-applied record yet, so it checks `config.json`, records it and applies it; after that, edits wait until you apply them (see [Reload](reload.md#reload)). Each persona starts fresh once. Pre-persona rows are kept and never resumed.
181
181
 
182
- This start also moves the old state directory: `~/.claude/channels/slack` is renamed to `~/.config/cscb`, a symbolic link to it is left at the old name, and the server logs one `[slack] state-migrate: moved the state directory from …` line to `~/.config/cscb/server.log`. Edit `config.json` and the other state files through `~/.config/cscb` after it.
182
+ This start also moves the old state directory: `~/.claude/channels/slack` is renamed to `~/.config/claude-slack-channel-bots`, a symbolic link to it is left at the old name, and the server logs one `[slack] state-migrate: moved the state directory from …` line to `~/.config/claude-slack-channel-bots/server.log`. Edit `config.json` and the other state files through `~/.config/claude-slack-channel-bots` after it.
183
183
  3. **The post-install check (operator action).** Once every agent has been started again, confirm that `agent-director list --state pending` shows a `launch_started_at` on every row. Record the result in the switch-over log. A row without one is a human's to look at, and the persona whose row it is is held (see "A persona posts a *Held: launch start not recorded* notice" and "How a hold ends" in [Troubleshooting](troubleshooting.md#troubleshooting)).
184
184
 
185
185
  #### Step 11: Schedule the daily expire
@@ -266,12 +266,12 @@ Revert the shared orchestrator prompt's "hold until after" wording that switch-o
266
266
 
267
267
  #### Step 8: Reinstall the previous CSCB
268
268
 
269
- 1. Move aside `config.json.last-applied` and `retired-keys.json` (see [Files beside the config file](reload.md#files-beside-the-config-file)), which are in `~/.config/cscb` after the new CSCB's first start.
269
+ 1. Move aside `config.json.last-applied` and `retired-keys.json` (see [Files beside the config file](reload.md#files-beside-the-config-file)), which are in `~/.config/claude-slack-channel-bots` after the new CSCB's first start.
270
270
  2. Reinstall the previous CSCB, the version switch-over step 1 recorded, or else the version the host ran before, without starting it:
271
271
  ```sh
272
272
  bun install -g claude-slack-channel-bots@<the previous version>
273
273
  ```
274
- 3. Put back what switch-over step 1 saved: the pre-persona `config.json`, the crontable, the `/interject` callers (the host crontab's `curl` lines included), `access.json` and the Slack token environment variables. Put `config.json`, the crontable and `access.json` back in the old state directory, by its old name, `~/.claude/channels/slack`: after the new CSCB's first start that name is a symbolic link to `~/.config/cscb`, and the previous CSCB reads its files through the link. Leave the link in place, and do not make a directory at the old name.
274
+ 3. Put back what switch-over step 1 saved: the pre-persona `config.json`, the crontable, the `/interject` callers (the host crontab's `curl` lines included), `access.json` and the Slack token environment variables. Put `config.json`, the crontable and `access.json` back in the old state directory, by its old name, `~/.claude/channels/slack`: after the new CSCB's first start that name is a symbolic link to `~/.config/claude-slack-channel-bots`, and the previous CSCB reads its files through the link. Leave the link in place, and do not make a directory at the old name.
275
275
  4. Where switch-over step 1's copy of a file is missing, the operator rebuilds the pre-persona file by hand from the persona configuration, reversing the manual conversion in [Upgrading to personas](#upgrading-to-personas). No tooling does this: CSCB ships no conversion tooling in either direction.
276
276
 
277
277
  #### Step 9: Start the previous CSCB
@@ -284,7 +284,7 @@ claude-slack-channel-bots start
284
284
 
285
285
  ### Upgrading to personas
286
286
 
287
- 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/cscb`.
287
+ 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`.
288
288
 
289
289
  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".
290
290
  2. **Pick persona names whose keys don't start with one another.** The configuration check rejects such a pair. If your bots were named `horde`, `horde_admin`, …, don't name a persona `horde` beside `horde_admin`: give the shorter name a suffix, such as `horde_main` (see [Persona name and key](configuration.md#persona-name-and-key)).
package/docs/reload.md CHANGED
@@ -4,7 +4,7 @@ Saving `config.json` doesn't change what runs. The server runs the last configur
4
4
 
5
5
  ## Files beside the config file
6
6
 
7
- These files sit in the same directory as `config.json` (`~/.config/cscb/` by default, or `SLACK_STATE_DIR`). Never edit them by hand.
7
+ These files sit in the same directory as `config.json` (`~/.config/claude-slack-channel-bots/` by default, or `SLACK_STATE_DIR`). Never edit them by hand.
8
8
 
9
9
  | File | What it is |
10
10
  |---|---|
@@ -47,8 +47,8 @@ While the server runs, it checks `config.json` and each credentials file the fil
47
47
  To see what is pending:
48
48
 
49
49
  ```sh
50
- cat ~/.config/cscb/config.json.pending
51
- grep -E 'reload-(preview|invalid|nothing-pending)' ~/.config/cscb/server.log | tail
50
+ cat ~/.config/claude-slack-channel-bots/config.json.pending
51
+ grep -E 'reload-(preview|invalid|nothing-pending)' ~/.config/claude-slack-channel-bots/server.log | tail
52
52
  ```
53
53
 
54
54
  ## Reading the preview
@@ -63,7 +63,7 @@ A configuration change is pending; nothing has been applied. personas: 1 added,
63
63
  DESTRUCTIVE: persona "scribe" (key=scribe) is removed: the persona will be retired: its session stopped and never resumed.
64
64
  persona "helper" (key=helper) is added but cannot come up: working directory does not exist.
65
65
  persona "planner" (key=planner): channels changed: applied in place immediately, instance kept.
66
- persona "reviewer" (key=reviewer): credentials file "/home/operator/.config/cscb/reviewer-credentials.json" changed: a new connection opens, then the old one closes, instance kept.
66
+ persona "reviewer" (key=reviewer): credentials file "/home/operator/.config/claude-slack-channel-bots/reviewer-credentials.json" changed: a new connection opens, then the old one closes, instance kept.
67
67
  server-wide setting port changed: once applied, it is recorded and takes effect at the next server start after that.
68
68
  server-wide setting claude_config_dir changed: inherited by "planner" (key=planner), "reviewer" (key=reviewer); takes effect at each one's next launch, which starts fresh (the conversation is not resumed), instance kept until then.
69
69
  ```
@@ -104,7 +104,7 @@ Paths in the preview are absolute: a `~` in `config.json` is shown expanded. In
104
104
  To apply a pending change, rename `config.json.pending` to `config.json.apply` in the same directory, with the server running:
105
105
 
106
106
  ```sh
107
- cd "${SLACK_STATE_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/cscb}" && mv config.json.pending config.json.apply
107
+ cd "${SLACK_STATE_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/claude-slack-channel-bots}" && mv config.json.pending config.json.apply
108
108
  ```
109
109
 
110
110
  Read the preview first. The server picks the confirmation up at its next check, within about 5 seconds; a check still running an earlier apply delays it, so `reload-applied` can come minutes later. It deletes the confirmation and applies it without a restart; next-launch and server-wide settings are recorded and take effect later, except the switch `allow_invited_channels`, which applies in place at once (see [What a confirmation applies](#what-a-confirmation-applies)).
@@ -114,7 +114,7 @@ You can direct an agent to do the rename for you. Nothing has to be computed, co
114
114
  Each confirmation logs one of these lines in `server.log`:
115
115
 
116
116
  ```sh
117
- grep -E 'reload-(applied|noop|invalid|stale-confirmation|record-write-failed)' "${SLACK_STATE_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/cscb}/server.log" | tail
117
+ grep -E 'reload-(applied|noop|invalid|stale-confirmation|record-write-failed)' "${SLACK_STATE_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/claude-slack-channel-bots}/server.log" | tail
118
118
  ```
119
119
 
120
120
  | Line | Meaning |
@@ -4,10 +4,10 @@ The server fires scheduled prompts into personas once per minute, reading them f
4
4
 
5
5
  ## The crontable
6
6
 
7
- Schedules live in the crontable file at `cron_table_path`. Without that key the crontable is `crontab` in the state directory, `~/.config/cscb/crontab` by default, outside `~/.claude`, so a bot appending a schedule doesn't trigger Claude Code's approval prompt for writes under `~/.claude`. Set `cron_table_path` in `config.json` to put it anywhere else (see [Server-wide settings](server-settings.md#server-wide-settings)).
7
+ Schedules live in the crontable file at `cron_table_path`. Without that key the crontable is `crontab` in the state directory, `~/.config/claude-slack-channel-bots/crontab` by default, outside `~/.claude`, so a bot appending a schedule doesn't trigger Claude Code's approval prompt for writes under `~/.claude`. Set `cron_table_path` in `config.json` to put it anywhere else (see [Server-wide settings](server-settings.md#server-wide-settings)).
8
8
 
9
9
  ```sh
10
- cat ~/.config/cscb/crontab
10
+ cat ~/.config/claude-slack-channel-bots/crontab
11
11
  ```
12
12
 
13
13
  At start the server creates the state directory. It creates the crontable on first boot if it is absent, with a self-documenting comment header describing the line format. See [Crontable format](#crontable-format) below for the full reference. For a `cron_table_path` you set, the directory must already exist.
@@ -86,7 +86,7 @@ An existing crontable also keeps its old comment header, which still tells bots
86
86
  The prompt-file path resolves as follows:
87
87
 
88
88
  - A leading `~` expands to the home directory.
89
- - A **relative** path resolves against the **crontable's own directory** — not `$HOME`. This is a deliberate divergence from system cron's convention, so you can keep a `prompts/` directory alongside the crontable and reference it as `prompts/standup.md`. With the default location that directory is `~/.config/cscb/prompts/`.
89
+ - A **relative** path resolves against the **crontable's own directory** — not `$HOME`. This is a deliberate divergence from system cron's convention, so you can keep a `prompts/` directory alongside the crontable and reference it as `prompts/standup.md`. With the default location that directory is `~/.config/claude-slack-channel-bots/prompts/`.
90
90
  - An **absolute** path is used as-is.
91
91
 
92
92
  ## How fires appear
@@ -124,7 +124,7 @@ Each load also writes one `warn` line for each line with no persona list, naming
124
124
  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:
125
125
 
126
126
  ```sh
127
- grep undeliverable ~/.config/cscb/cron.log
127
+ grep undeliverable ~/.config/claude-slack-channel-bots/cron.log
128
128
  ```
129
129
 
130
130
  ## Delivery semantics
@@ -25,7 +25,7 @@ These top-level fields apply to the whole server. A confirmed change to one take
25
25
  | `agent_director_poll_interval_ms` | number | `1000` | Poll interval (ms) for the agent-director permission relay tick. Must be a positive integer in `[200, 3_600_000]`. Replaces the pre-rename `claude_director_poll_interval_ms` — the old name is rejected at startup. |
26
26
  | `agent_director_call_timeout_ms` | number | `60000` | How long (ms) CSCB waits on each agent-director call it makes for its personas, in the server and in `stop --stop-bots` and `clean_restart`. Must be an integer in `[1000, 3_600_000]`; out-of-range values are rejected at load. It should be greater than the need that agent-director's timing settings give; see [Sizing the agent-director call timeout](agent-director.md#sizing-the-agent-director-call-timeout). |
27
27
  | `stop_hook_bootstrap` | boolean | `true` | Default for every persona: whether the persona gets the Slack Reply Guard reminder (see [Slack Reply Guard (Stop hook)](bots.md#slack-reply-guard-stop-hook)). The value applies per persona, from the persona's first launch after the change is applied (see [Reload](reload.md#reload)). A persona's own `stop_hook_bootstrap` overrides this value. Non-boolean values are rejected at startup. |
28
- | `cron_table_path` | string | `~/.config/cscb/crontab` | Path to the crontable for the built-in cron scheduler (`cscb_cron`). When absent, it is `crontab` in the state directory, beside `config.json`: `~/.config/cscb/crontab` by default, outside `~/.claude`, so a bot's edit is not a write under `~/.claude`, which Claude Code asks the user to approve. A path you set is used as written, with `~` expanded like other path keys: the server never creates its directory or moves a crontable to it. The resolved path is exported into every managed session as `CSCB_CRONTABLE_PATH` so bots can find the crontable and self-schedule (see [Scheduled Prompts](scheduled-prompts.md#scheduled-prompts-cscb_cron)). Must be a non-empty string when set. |
28
+ | `cron_table_path` | string | `~/.config/claude-slack-channel-bots/crontab` | Path to the crontable for the built-in cron scheduler (`cscb_cron`). When absent, it is `crontab` in the state directory, beside `config.json`: `~/.config/claude-slack-channel-bots/crontab` by default, outside `~/.claude`, so a bot's edit is not a write under `~/.claude`, which Claude Code asks the user to approve. A path you set is used as written, with `~` expanded like other path keys: the server never creates its directory or moves a crontable to it. The resolved path is exported into every managed session as `CSCB_CRONTABLE_PATH` so bots can find the crontable and self-schedule (see [Scheduled Prompts](scheduled-prompts.md#scheduled-prompts-cscb_cron)). Must be a non-empty string when set. |
29
29
  | `cron_log_path` | string | `<config dir>/cron.log` | Path to the `cscb_cron` log file. Defaults to `cron.log` in the directory of the loaded `config.json`, wherever the crontable is. `~` is expanded like other path keys. Must be a non-empty string when set. |
30
30
  | `cron_log_max_bytes` | number | — | Size cap in bytes for the cron log. Once a line takes the log past the cap, the server drops its oldest whole lines until it fits. The newest line is always kept, even when it alone is larger than the cap. Nothing is rotated or archived, so dropped lines are gone. Absent means no cap: the log only grows. Must be a positive integer when set. |
31
31
  | `ack_reaction` | string | — | Emoji name, without colons (for example `"eyes"`), of the acknowledgement reaction. When set, each persona a message is dispatched to adds the reaction under its own Slack identity once the message has reached its instance, not on receipt, so a message that reaches several personas carries one reaction per persona. A message that isn't dispatched gets no reaction: one lost because the persona's instance is down, or one the persona doesn't receive. Messages sent through `/interject` or cron aren't Slack messages and get none either. A persona's first `reply` in that conversation carrying the message's `message_id` removes that persona's reaction only; other personas' reactions stay until they reply. Absent means no acknowledgement. Must be non-empty when set. |
@@ -41,8 +41,8 @@ Runtime options are read from environment variables. None of them is required. S
41
41
 
42
42
  | Variable | Description |
43
43
  |---|---|
44
- | `SLACK_STATE_DIR` | Override the directory where `config.json` and runtime state are stored. Defaults to `~/.config/cscb` (see `XDG_CONFIG_HOME` below), outside `~/.claude`, where Claude Code asks the user before every write. The crontable defaults to `crontab` in this directory (see `cron_table_path` under [Server-wide settings](#server-wide-settings)). |
45
- | `XDG_CONFIG_HOME` | The standard XDG configuration directory. With `SLACK_STATE_DIR` unset and `XDG_CONFIG_HOME` an absolute path, the state directory, and the crontable in it, is `$XDG_CONFIG_HOME/cscb` instead of `~/.config/cscb`. An empty or relative value is ignored. |
44
+ | `SLACK_STATE_DIR` | Override the directory where `config.json` and runtime state are stored. Defaults to `~/.config/claude-slack-channel-bots` (see `XDG_CONFIG_HOME` below), outside `~/.claude`, where Claude Code asks the user before every write. The crontable defaults to `crontab` in this directory (see `cron_table_path` under [Server-wide settings](#server-wide-settings)). |
45
+ | `XDG_CONFIG_HOME` | The standard XDG configuration directory. With `SLACK_STATE_DIR` unset and `XDG_CONFIG_HOME` an absolute path, the state directory, and the crontable in it, is `$XDG_CONFIG_HOME/claude-slack-channel-bots` instead of `~/.config/claude-slack-channel-bots`. An empty or relative value is ignored. |
46
46
  | `SLACK_DRY_RUN` | Set to `1` (or `true` / `yes`) to start the server without Slack. No credentials file is read and no Slack call is made. Each persona runs with a placeholder identity (`U000DRY_<key>`), and MCP tool calls (`reply`, `react`, etc.) and server notices are logged instead of sent. Useful for integration testing. |
47
47
  | `CSCB_LOG_MAX_BYTES` | Rotate `server.log` / `clean_restart.log` when the active file reaches this many bytes. Defaults to `10485760` (10 MiB). Values `<= 0` or non-numeric are ignored. |
48
48
  | `CSCB_LOG_KEEP` | Number of rotated generations to retain (`server.log.1` … `server.log.N`). Defaults to `5`. Set to `0` to keep none (the log is truncated instead of rolled). Values `< 0` or non-numeric are ignored. |
@@ -123,7 +123,7 @@ A regression in some Claude Code releases (for example v2.1.120). Set `resume_en
123
123
 
124
124
  ## Server log rotation
125
125
 
126
- The server daemon writes runtime output to `~/.config/cscb/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.
126
+ 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.
127
127
 
128
128
  `stop --stop-bots` and `clean_restart` append their bot-teardown lines to `server.log` while the server is stopped (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.
129
129
 
@@ -133,4 +133,4 @@ Note this covers only `server.log` / `clean_restart.log`. `startup-errors.log` a
133
133
 
134
134
  ## Startup errors
135
135
 
136
- CSCB writes startup errors to `~/.config/cscb/startup-errors.log` (under `SLACK_STATE_DIR` when it is set) and to stderr, one timestamped line each. The file is append-only and never rotated by CSCB; copy `docs/logrotate-startup-errors.conf` into `/etc/logrotate.d/` for host-level rotation. A fatal class, such as a refused agent-director binary or `retired-keys-unreadable`, stops the process; the others are recorded and the start continues. [Every class, what it means and what to do](../skills/debug-slack-channel-bots/SKILL.md#startup-errors-startup-errorslog).
136
+ CSCB writes startup errors to `~/.config/claude-slack-channel-bots/startup-errors.log` (under `SLACK_STATE_DIR` when it is set) and to stderr, one timestamped line each. The file is append-only and never rotated by CSCB; copy `docs/logrotate-startup-errors.conf` into `/etc/logrotate.d/` for host-level rotation. A fatal class, such as a refused agent-director binary or `retired-keys-unreadable`, stops the process; the others are recorded and the start continues. A refused state-directory move at the first start after an upgrade is the exception to where the file is: it is logged in the directory the CLI uses before the move, normally the old one (see [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)). [Every class, what it means and what to do](../skills/debug-slack-channel-bots/SKILL.md#startup-errors-startup-errorslog).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-slack-channel-bots",
3
- "version": "0.15.0",
3
+ "version": "0.15.1",
4
4
  "description": "Run several Claude Code personas, each its own Slack app, from one server via Socket Mode",
5
5
  "type": "module",
6
6
  "bin": {