claude-slack-channel-bots 0.15.0 → 0.16.0
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 +7 -7
- package/docs/agent-director.md +12 -4
- package/docs/bots.md +3 -2
- package/docs/channel-modes.md +4 -4
- package/docs/cli.md +7 -7
- package/docs/configuration.md +5 -5
- package/docs/migration.md +41 -62
- package/docs/reload.md +6 -6
- package/docs/scheduled-prompts.md +4 -4
- package/docs/server-settings.md +5 -5
- package/docs/troubleshooting.md +8 -6
- package/package.json +2 -2
- package/skills/debug-slack-channel-bots/SKILL.md +183 -154
- package/skills/install-cscb/SKILL.md +6 -6
- package/skills/setup-slack-channel-bots/SKILL.md +12 -11
- package/src/ad-config-file.ts +3 -3
- package/src/ad-description-phrases.ts +3 -0
- package/src/ad-error-class.ts +29 -20
- package/src/ad-settings.ts +10 -8
- package/src/ad-version-gate.ts +22 -8
- package/src/agent-director-client.ts +3 -13
- package/src/agent-director-errors.ts +14 -21
- package/src/agent-director-startup.ts +13 -5
- package/src/agent-director-template.ts +9 -8
- package/src/checked-kill.ts +4 -4
- package/src/cli-teardown.ts +1 -1
- package/src/cli.ts +10 -8
- package/src/config.ts +17 -12
- package/src/conflict-latch.ts +5 -1
- package/src/cron-bootstrap.ts +1 -1
- package/src/install-check.ts +4 -3
- package/src/jsonl-persistence-check.ts +21 -21
- package/src/kill-failure-alert.ts +2 -2
- package/src/live-row-sequence.ts +3 -3
- package/src/outage-state.ts +2 -2
- package/src/permission-action-id.ts +10 -10
- package/src/permission-click-handler.ts +29 -23
- package/src/permission-poller.ts +166 -150
- package/src/permission-trail.ts +2 -2
- package/src/persona-identity.ts +2 -2
- package/src/postinstall.ts +1 -1
- package/src/retired-keys.ts +1 -1
- package/src/row-read-rules.ts +3 -3
- package/src/server.ts +18 -12
- package/src/session-manager.ts +77 -75
- package/src/session-transcript.ts +6 -6
- package/src/startup-errors.ts +1 -1
- package/src/state-dir-migration.ts +373 -72
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/
|
|
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
|
|
|
@@ -47,8 +47,8 @@ A single HTTP MCP server that runs several independent Claude Code bots, called
|
|
|
47
47
|
## Prerequisites
|
|
48
48
|
|
|
49
49
|
- [Bun](https://bun.sh) `>= 1.0.21` (agent-director minimum)
|
|
50
|
-
- [Claude Code](https://claude.ai/code) 2.1.
|
|
51
|
-
- [`agent-director`](https://github.com/gabemahoney/agent-director)
|
|
50
|
+
- [Claude Code](https://claude.ai/code) 2.1.296 or later for the workers, installed and authenticated: the minimum agent-director states for its exec-form hooks, and the version the fleet runs. A Claude Code too old for exec-form hooks (older than 2.1.139) has its hooks ignored, so every launch stays `pending`. The `claude` on the workers' `PATH` must be Claude Code's native binary or a wrapper that `exec`s it: a launcher or shim that runs Claude Code as a child process makes agent-director ignore every hook (`ad.hook.ignored` with the reason `pid_mismatch`), so every launch stays `pending`.
|
|
51
|
+
- [`agent-director`](https://github.com/gabemahoney/agent-director) 0.12.0 or later, **installed system-wide** as a prerequisite, like `git` or `docker`. The npm `agent-director` package CSCB depends on is the client only: it finds the system-installed binary at startup and refuses to start when the binary is missing, too old, or unreachable. This release pins the client to `agent-director@0.12.0` and requires the CLI at 0.12.0 or later, installed on the host together with it, and the two are rolled back together; CSCB changes no agent-director code (see "Switching over to agent-director Phase 1" in [Migration](docs/migration.md#migration)). Every agent on the host, with every long-running agent-director process (`agent-director serve` included), is stopped before either binary change (the Phase 1 install, and the rollback's restore of the previous binary) and started again after it. The startup gate refuses a binary below the client's own minimum (`min_binary_version` in the client's `dist/version-floor.json`) or below 0.12.0, and names the required version (see [Startup errors](docs/troubleshooting.md#startup-errors)). To check the install before you start, run `bun run install-check` (see [Checking your agent-director install](docs/agent-director.md#checking-your-agent-director-install)).
|
|
52
52
|
- [tmux](https://github.com/tmux/tmux) 3.2 or later, with `remain-on-exit` off. agent-director runs it; CSCB starts no tmux process. agent-director does not depend on tmux's `base-index` or `pane-base-index`, so their values don't matter.
|
|
53
53
|
- Slack workspace admin access (to create and configure one Slack app per persona)
|
|
54
54
|
- **cozempic** (optional) — Python 3.10+ and `pip install cozempic` — used by JSONL path resolution helpers retained for downstream callers.
|
|
@@ -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/
|
|
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/
|
|
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/
|
|
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}/
|
|
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.
|
package/docs/agent-director.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# agent-director
|
|
2
2
|
|
|
3
|
+
CSCB requires agent-director CLI 0.12.0 or later and pins its TypeScript client to `agent-director@0.12.0`. Workers require Claude Code 2.1.296 or later. Upgrade the CLI with its released installer before upgrading CSCB; see [Migration](migration.md#migration).
|
|
4
|
+
|
|
3
5
|
CSCB runs every bot through [agent-director](https://github.com/gabemahoney/agent-director), installed system-wide. This page covers checking that install, the `install-cscb` skill that walks you through a failed check, and the agent-director settings CSCB reads.
|
|
4
6
|
|
|
5
7
|
## Checking your agent-director install
|
|
@@ -10,10 +12,10 @@ Before starting the server, you can confirm `agent-director` is installed system
|
|
|
10
12
|
bun run install-check
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
The script finds the system-installed agent-director binary and reads its version, then judges it in two steps: first against the agent-director client's own minimum (`min_binary_version` in the installed client's `dist/version-floor.json`), then against CSCB's Phase 1 floor. `/publish`'s preflight check makes the same decision. There are three outcomes:
|
|
15
|
+
The script finds the system-installed agent-director binary and reads its version, then judges it in two steps: first against the agent-director client's own minimum (`min_binary_version` in the installed client's `dist/version-floor.json`), then against CSCB's Phase 1 floor. `/publish`'s preflight check makes the same decision. The released client's minimum is 0.12.0. There are three outcomes:
|
|
14
16
|
|
|
15
17
|
- **Pass.** The binary meets both. The script exits 0 and prints one block naming `agent-director`, the resolved binary path, the version found and, on the line labelled `floor:`, the agent-director client's minimum (not CSCB's Phase 1 floor).
|
|
16
|
-
- **Pass with a note.** The
|
|
18
|
+
- **Pass with a note.** The released client admits the development placeholder `0.0.0-dev` above any minimum, but CSCB's numeric Phase 1 floor refuses it. Ordinary older releases and 0.12.0 release candidates fail the client's minimum first. The script still exits 0 and prints the same block, followed by a note: the server will not start on this binary until agent-director Phase 1 is installed; see the docs/migration.md section "Switching over to agent-director Phase 1".
|
|
17
19
|
- **Fail.** The script writes one of the class labels below, with its message, to stderr and exits non-zero:
|
|
18
20
|
- `ad-system-install-not-found` — no agent-director on PATH or at the standard install path. The message points to the block ["The publishing host"](migration.md#the-publishing-host) in the docs/migration.md section "Switching over to agent-director Phase 1", which covers a host with no agent-director. The stderr also points at the install-cscb skill.
|
|
19
21
|
- `ad-system-install-too-old` — the binary is below the agent-director client's own minimum. The message names the version found, the version the client requires, the binary path and the docs/migration.md section "Switching over to agent-director Phase 1", which is how agent-director is installed for this CSCB release. The stderr points at the skill.
|
|
@@ -64,7 +66,7 @@ The skill first states that this CSCB release and agent-director Phase 1
|
|
|
64
66
|
are installed, and rolled back, together, by the docs/migration.md sections
|
|
65
67
|
"Switching over to agent-director Phase 1" and "Rolling back the
|
|
66
68
|
switch-over", which it points to by title. It names the agent-director
|
|
67
|
-
client CSCB pins, `agent-director@0.
|
|
69
|
+
client CSCB pins, `agent-director@0.12.0`, which comes installed with
|
|
68
70
|
CSCB; the skill runs no install or upgrade of the client or the binary.
|
|
69
71
|
|
|
70
72
|
The skill calls `bun run install-check` on each iteration. On a pass that
|
|
@@ -95,7 +97,7 @@ who haven't yet installed CSCB at all.
|
|
|
95
97
|
|
|
96
98
|
## agent-director's timing settings
|
|
97
99
|
|
|
98
|
-
agent-director keeps its timing settings in the `[tmux]` table of `~/.agent-director/config.toml`. They are agent-director's settings, not CSCB configuration: CSCB only reads them, from the file under the HOME the server runs in.
|
|
100
|
+
agent-director keeps its timing settings in the `[tmux]` table of `~/.config/agent-director/config.toml`. They are agent-director's settings, not CSCB configuration: CSCB only reads them, from the file under the HOME the server runs in. Set HOME to a nonempty absolute path: CSCB refuses to read settings through an unset, empty or relative HOME, and the agent-director installer and uninstaller exit 2 for those values.
|
|
99
101
|
|
|
100
102
|
The server reads the table when it starts and every 120 s after that, whatever `health_check_interval` is (`0` included), so a change on the host is used within about 120 s (each read follows the binary re-check, which runs 120 s after the previous one ends and can take up to its 30 s time limit). It applies agent-director's own rule: a missing file, a missing key or `0` means agent-director's default. At the first read it accepts, and at each later accepted read that changes any of them, the server writes one line to `server.log` with the nine `[tmux]` values in effect; a read that changes only `[pause] timeout_seconds` (see [Sizing the agent-director call timeout](#sizing-the-agent-director-call-timeout)) writes none.
|
|
101
103
|
|
|
@@ -169,3 +171,9 @@ Either way the server still starts, and no value changes. The check runs only at
|
|
|
169
171
|
To fix it, raise `agent_director_call_timeout_ms` in `config.json` above the need and confirm the change (see [Reload](reload.md#reload)). `stop --stop-bots` and `clean_restart` use the new value at once; the server uses it from its next start.
|
|
170
172
|
|
|
171
173
|
For the second line, give `[pause] timeout_seconds` a positive whole number, or remove it for the 30 s default; the next start checks the setting against the need that gives.
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
AD 0.12 keeps archived sessions in `prior_sessions` across same-agent reuse. A fresh spawn uses a new current session; archived sessions are available for inspection and are never resumed as a fallback. A launch with no recorded tmux server or pane can leave an abandoned session: AD reports it unavailable until the starting-session bound, then refuses it as an own-id conflict. CSCB latches that conflict for human review and retries only through the existing own-id recheck policy.
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
An unmessaged conversation created by same-agent reuse can report `transcript_status: rotated`: its current transcript has not been written, but earlier sessions remain inspectable. A resume with missing current-session paths then returns `ErrJsonlMissing`. `ErrJsonlNeverWritten` requires both an empty current recorded path and empty visible prior history. CSCB still diagnoses missing transcripts before reusing the row, reports uncertainty when evidence is insufficient, and never resumes an archived session as a fallback.
|
package/docs/bots.md
CHANGED
|
@@ -90,8 +90,9 @@ When Claude Code requires tool approval, the permission relay surfaces an intera
|
|
|
90
90
|
|
|
91
91
|
1. When a bot's Claude Code asks for a tool permission, agent-director holds the request, and CSCB picks it up within `agent_director_poll_interval_ms` (default 1000 ms).
|
|
92
92
|
2. CSCB posts the prompt as the persona that owns the bot, to its destination: its destination channel (its `permission_prompts` in declarative mode, its `invited.permission_prompts` in fungible mode), or, for a `"dm"` destination, a DM from the persona's app to its `dm.contact`. The server opens that DM if none exists yet, so a DM-only persona's first prompt is delivered too. Each persona follows its own setting.
|
|
93
|
-
3. The operator clicks Allow / Deny in Slack, in the channel or the DM; the buttons work the same in both. CSCB passes the decision
|
|
94
|
-
4.
|
|
93
|
+
3. The operator clicks Allow / Deny in Slack, in the channel or the DM; the buttons work the same in both. CSCB passes the decision through agent-director. It shows Allowed or Denied only after delivery is confirmed. When delivery is not yet confirmed, the message stays pending while CSCB polls for delivery or closure.
|
|
94
|
+
4. A request that falls back to the tmux pane gets a notice without Slack buttons. Read the pane and follow the [permission recovery entry](../skills/debug-slack-channel-bots/SKILL.md#agent-director-permission-recovery); CSCB does not answer it automatically.
|
|
95
|
+
5. If a prompt closes for any reason other than a Slack click, the next check replaces the buttons with the verdict: "⏱ *Permission* — Timed out", "🪦 *Permission* — Session ended", "*Permission* — Allowed", "*Permission* — Denied by operator", or "*Permission* — Denied (closed)" when the reason is unknown.
|
|
95
96
|
|
|
96
97
|
The prompt names the tool and shows its input: Bash's command, Edit's or Write's file path, or for any other tool the input as JSON, up to 500 characters. An input too long for Slack's 3000-character limit on a message section is cut to fit and followed by `… (truncated, <shown> of <total> chars shown)`; the rest is not shown in Slack.
|
|
97
98
|
|
package/docs/channel-modes.md
CHANGED
|
@@ -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/
|
|
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/
|
|
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/
|
|
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/
|
|
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
|
@@ -14,7 +14,7 @@ missing prerequisite: config.json not found at <path>, and no config.json.last-a
|
|
|
14
14
|
|
|
15
15
|
`start` reads no Slack token. The server checks the configuration, and each persona's credentials file, once it runs.
|
|
16
16
|
|
|
17
|
-
The server first runs the agent-director startup gate: it imports `agent-director`, constructs the singleton Client (which probes the system binary's version and refuses a binary below the client's own minimum), reads the binary's version from the built client and refuses a binary below CSCB's Phase 1 floor, and verifies `~/.agent-director/state.db` is owned by the current user. Failures land in `startup-errors.log` (see [Startup errors](troubleshooting.md#startup-errors)). agent-director enforces tmux availability at spawn time. The server then loads the configuration and starts listening. With a last-applied record it runs the record; without one it checks `config.json`, records it and applies it (see [Reload](reload.md#reload)). Only then does it write its PID to `STATE_DIR/server.pid`. Conversation context is preserved across server restarts when possible.
|
|
17
|
+
The server first runs the agent-director startup gate: it imports `agent-director`, constructs the singleton Client (which probes the system binary's version and refuses a binary below the client's own minimum), reads the binary's version from the built client and refuses a binary below CSCB's Phase 1 floor, and verifies `~/.config/agent-director/state.db` is owned by the current user. Failures land in `startup-errors.log` (see [Startup errors](troubleshooting.md#startup-errors)). agent-director enforces tmux availability at spawn time. The server then loads the configuration and starts listening. With a last-applied record it runs the record; without one it checks `config.json`, records it and applies it (see [Reload](reload.md#reload)). Only then does it write its PID to `STATE_DIR/server.pid`. Conversation context is preserved across server restarts when possible.
|
|
18
18
|
|
|
19
19
|
`start` waits up to 30 seconds for that PID file. The outcomes are:
|
|
20
20
|
|
|
@@ -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/
|
|
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/
|
|
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:
|
|
@@ -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 `
|
|
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).
|
|
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
|
|
|
@@ -76,7 +76,7 @@ Runs the [precheck](#precheck-before-stopping-bots), then stops the server, grac
|
|
|
76
76
|
claude-slack-channel-bots clean_restart
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
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 `
|
|
79
|
+
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
80
|
|
|
81
81
|
`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.
|
|
82
82
|
|
|
@@ -129,7 +129,7 @@ Either way the last line follows, and the command exits 1. Rows are never delete
|
|
|
129
129
|
|
|
130
130
|
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
131
|
|
|
132
|
-
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,
|
|
132
|
+
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
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.
|
|
134
134
|
|
|
135
135
|
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:
|
|
@@ -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/
|
|
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`.
|
package/docs/configuration.md
CHANGED
|
@@ -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/
|
|
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/
|
|
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/
|
|
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/
|
|
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"
|
|
@@ -199,7 +199,7 @@ Use `--console` instead of `--claudeai` for a Console account. When neither the
|
|
|
199
199
|
|
|
200
200
|
- A directory that doesn't exist yet is fine when its parent exists.
|
|
201
201
|
- A persona whose `claude_config_dir` can't be resolved to a real path (for example, a symlink on its path that points to nothing) is held: it closes or never opens its Slack connection and receives nothing, and `server.log` shows `persona-config-dir-unresolvable`. It reconnects once the directory resolves, with no restart.
|
|
202
|
-
- A confirmed change to a persona's effective `claude_config_dir` makes it start a new conversation on the same instance at its next launch. Nothing is deleted: the old conversation stays in the old directory,
|
|
202
|
+
- A confirmed change to a persona's effective `claude_config_dir` makes it start a new conversation on the same instance at its next launch. Nothing is deleted: the old conversation stays in the old directory, with prior sessions retained in the same AD life.
|
|
203
203
|
- The Slack Reply Guard never installs its hook in `~/.claude`, so a persona whose directory resolves there gets no reminder (see the debugging skill's [How the guard is installed and what it reads](../skills/debug-slack-channel-bots/SKILL.md#how-the-guard-is-installed-and-what-it-reads)).
|
|
204
204
|
|
|
205
205
|
**`stop_hook_bootstrap`** turns the [Slack Reply Guard](bots.md#slack-reply-guard-stop-hook) reminder on (`true`, the default) or off for the persona. It applies to that persona alone, even when it shares its `claude_config_dir` with other personas. A running bot keeps the value it was launched with until it is relaunched. See [Personas that answer without `reply`](bots.md#personas-that-answer-without-reply--opt-them-out) for when to turn it off.
|