@sellable/install 0.1.327 → 0.1.329

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.
@@ -0,0 +1,169 @@
1
+ # Hermes Slack Profile Scoping
2
+
3
+ Use this when creating or updating customer Hermes profiles that need Slack
4
+ access.
5
+
6
+ ## Default Rule
7
+
8
+ For Sellable-managed customer channels, use one dedicated Slack app/token pair
9
+ per active Hermes customer profile. Run native `hermes -p <profile> gateway run`
10
+ for that profile only. Do not run multiple active Hermes profile gateways
11
+ against the same `SLACK_APP_TOKEN`.
12
+
13
+ The customer's Slack app is bound to the exact Slack channel id and the
14
+ customer's profile-local Sellable MCP config. Customer profiles must not store
15
+ or read Sellable Admin MCP credentials, admin Slack app tokens, or sibling
16
+ profile config.
17
+
18
+ The shared dispatcher remains a fallback/research path only. Use it only when
19
+ Sellable Admin explicitly owns one shared listener and route registry.
20
+
21
+ The 2026-07-06 Hostinger POC proved the native Hermes listener for the
22
+ `sellable-admin` profile with the existing `Sellable Reply Bot` app in
23
+ `#team-chat`: a human mention produced a new Hermes session and a threaded bot
24
+ reply. Treat that as proof that the gateway/listener path works for one owning
25
+ profile, not as approval for multiple active customer profiles sharing one app
26
+ token.
27
+
28
+ The same day, the `acme` profile reused the same redacted Slack token
29
+ fingerprints for an outbound-only smoke to `#sellable-acme` via:
30
+
31
+ ```bash
32
+ hermes --profile acme send --to slack:C0BFERDV3N0 --subject '[Hermes acme smoke]' ...
33
+ ```
34
+
35
+ That succeeded and is useful as an internal smoke test. It does not change the
36
+ inbound listener rule: each active customer profile needs its own native Slack
37
+ app token pair unless Sellable Admin deliberately chooses the dispatcher
38
+ fallback.
39
+
40
+ ## Which Slack Values Are Enough
41
+
42
+ For outbound sends and ordinary Slack Web API calls, the important value is the
43
+ profile-local `SLACK_BOT_TOKEN`.
44
+
45
+ For native Hermes live listening through Slack Socket Mode, the profile also
46
+ needs `SLACK_APP_TOKEN`, an app-level `xapp-...` token with `connections:write`.
47
+ `SLACK_APP_ID`, `SLACK_CLIENT_ID`, `SLACK_CLIENT_SECRET`,
48
+ `SLACK_SIGNING_SECRET`, `SLACK_VERIFICATION_TOKEN`, `SLACK_TEAM_ID`, and
49
+ `SLACK_OPERATOR_EMAIL` do not replace `SLACK_APP_TOKEN`.
50
+
51
+ ## Required Slack App Shape
52
+
53
+ Outbound Slack sends can work with fewer permissions. Native Hermes inbound
54
+ listening needs the Slack app itself to be configured for Socket Mode and event
55
+ delivery:
56
+
57
+ - Enable Socket Mode.
58
+ - Create an app-level token with `connections:write`.
59
+ - Install the bot with `app_mentions:read`, `channels:history`,
60
+ `channels:read`, `chat:write`, `groups:history`, `groups:read`,
61
+ `im:history`, `im:read`, `mpim:history`, `mpim:read`, and `users:read`.
62
+ - Subscribe bot events for `app_mention`, `message.channels`,
63
+ `message.groups`, `message.im`, and `message.mpim`.
64
+ - Reinstall the app after changing scopes or event subscriptions.
65
+
66
+ If the Slack app has `incoming-webhook`, Slack will ask for a webhook channel
67
+ during reinstall. Pick the profile home channel. That webhook selection does
68
+ not replace `SLACK_ALLOWED_CHANNELS`; keep the profile-local allowlist explicit.
69
+
70
+ ## Profile Bootstrap Command
71
+
72
+ Use the Sellable installer profile bootstrap:
73
+
74
+ ```bash
75
+ sellable hermes profile bootstrap \
76
+ --profile acme \
77
+ --profiles-root /srv/hermes/profiles \
78
+ --workspace-id ws_acme \
79
+ --workspace-name Acme \
80
+ --token-file /run/secrets/sellable-acme-token \
81
+ --slack-bot-token "$SLACK_BOT_TOKEN" \
82
+ --slack-app-token "$SLACK_APP_TOKEN" \
83
+ --slack-home-channel C0ACME12345 \
84
+ --slack-home-channel-name sellable-acme \
85
+ --slack-allowed-users U0OPERATOR1 \
86
+ --slack-require-mention true \
87
+ --json
88
+ ```
89
+
90
+ If `--slack-home-channel` is supplied and `--slack-allowed-channels` is omitted,
91
+ the installer writes `SLACK_ALLOWED_CHANNELS=<home-channel-id>` automatically.
92
+ That makes the profile fail closed to the customer channel by default.
93
+
94
+ Use `--slack-allowed-channels C...,G...` only when a profile is intentionally
95
+ allowed to listen in more than one channel. Pass Slack IDs, not `#channel-name`
96
+ strings or wildcards.
97
+
98
+ ## Resulting Profile Env
99
+
100
+ For the dedicated customer Slack app model, the profile-local `.env` should
101
+ contain only scoped Slack keys for that profile:
102
+
103
+ ```env
104
+ SLACK_BOT_TOKEN=...
105
+ SLACK_APP_TOKEN=...
106
+ SLACK_HOME_CHANNEL=C0ACME12345
107
+ SLACK_HOME_CHANNEL_NAME=sellable-acme
108
+ SLACK_ALLOWED_CHANNELS=C0ACME12345
109
+ SLACK_ALLOWED_USERS=U0OPERATOR1
110
+ SLACK_REQUIRE_MENTION=true
111
+ ```
112
+
113
+ Keep the file mode at `0600`. Do not copy raw tokens into planning docs, chat,
114
+ or committed artifacts. Record token fingerprints only.
115
+
116
+ The profile's Hermes MCP env must also include the profile-local Sellable
117
+ config, customer workspace lock, and fail-closed guard:
118
+
119
+ ```yaml
120
+ SELLABLE_CONFIG_PATH: /srv/hermes/profiles/acme/sellable/config.json
121
+ SELLABLE_CONFIGS_DIR: /srv/hermes/profiles/acme/sellable/configs
122
+ SELLABLE_LOCK_WORKSPACE_ID: ws_acme
123
+ SELLABLE_REQUIRE_WORKSPACE_LOCK: "1"
124
+ ```
125
+
126
+ `SELLABLE_REQUIRE_WORKSPACE_LOCK=1` means an unbound customer profile fails
127
+ closed before making Sellable API calls instead of falling back to shared or
128
+ admin config state. Only the `sellable-admin` profile should provision,
129
+ inspect, or repair other profiles.
130
+
131
+ For the shared dispatcher model, do not copy the shared `SLACK_BOT_TOKEN` or
132
+ `SLACK_APP_TOKEN` into customer profile `.env` files. The dispatcher owns those
133
+ tokens and route metadata decides the customer profile.
134
+
135
+ ## Shared Dispatcher Ownership
136
+
137
+ The shared Slack dispatcher and its route registry are fallback Sellable Admin
138
+ surfaces. This customer-facing installer must not create shared route bundles or
139
+ write shared listener tokens. Sellable Admin owns Slack app creation and profile
140
+ provisioning, then calls this installer for profile-local Sellable runtime
141
+ bootstrap inside the already-provisioned Hermes profile.
142
+
143
+ ## Verification
144
+
145
+ Run the installer and dispatcher UAT before publishing installer changes:
146
+
147
+ ```bash
148
+ npm run test:unit -- tests/install-package/agent-preferences.test.ts
149
+ scripts/run-phase92-hermes-profile-bootstrap-uat.sh --mode local-temp
150
+ scripts/run-phase92-hermes-profile-bootstrap-uat.sh --mode linux-shaped
151
+ scripts/run-phase031-hermes-slack-dispatcher-uat.sh --mode local-fixture
152
+ ```
153
+
154
+ Expected proof:
155
+
156
+ - profile-local Sellable config paths remain authoritative
157
+ - generated profile `.env` has `SLACK_HOME_CHANNEL`
158
+ - generated profile `.env` has `SLACK_ALLOWED_CHANNELS`
159
+ - `acme` allowlist points at the `sellable-acme` fixture channel id
160
+ - redaction scan passes
161
+
162
+ ## Current Phase 03 Status
163
+
164
+ Phase 03 proved the profile-scoped installer path, outbound Hermes send path,
165
+ and live Slack listener for the `sellable-admin` profile. Phase 03.1 now targets
166
+ dedicated native Slack apps per customer profile, profile-local Sellable MCP
167
+ locks, and fail-closed customer profile behavior so managed customer channels
168
+ can be onboarded through the VPS without local-only browser state, manual SSH
169
+ edits, or untracked processes.
package/README.md CHANGED
@@ -122,6 +122,17 @@ It creates:
122
122
  /srv/hermes/profiles/acme/.env # only when Slack token inputs are supplied
123
123
  ```
124
124
 
125
+ Bootstrap also writes `SELLABLE_LOCK_WORKSPACE_ID=<workspace-id>` and
126
+ `SELLABLE_REQUIRE_WORKSPACE_LOCK=1` into the profile's Hermes MCP env.
127
+ Customer profiles are therefore locked to their own Sellable workspace:
128
+ Sellable MCP requests are forced to that workspace, workspace switching/creation
129
+ is blocked, workspace listings are filtered, and a missing lock fails closed
130
+ instead of falling back to shared/admin config. Use the `sellable-admin` profile
131
+ for provisioning or cross-profile inspection.
132
+
133
+ See [`HERMES-SLACK-PROFILE-SCOPING.md`](./HERMES-SLACK-PROFILE-SCOPING.md) for
134
+ the customer Slack isolation contract and Socket Mode token requirements.
135
+
125
136
  If no token is supplied, bootstrap still creates a pending
126
137
  `sellable/config.json` so the profile path is concrete from the first MCP
127
138
  launch. Finish auth with:
@@ -142,6 +153,36 @@ sellable hermes profile bootstrap \
142
153
  --slack-app-token "$SLACK_APP_TOKEN"
143
154
  ```
144
155
 
156
+ The Slack app must also be configured for inbound Socket Mode delivery. Outbound
157
+ Slack Web API sends can work before this is complete, but Hermes will not hear
158
+ mentions until the app has Socket Mode enabled, an app-level token with
159
+ `connections:write`, bot scopes/events for `app_mention` plus channel/group/IM
160
+ message events, and a fresh workspace reinstall after scope or event changes.
161
+
162
+ Scope the profile to its customer channel at install time:
163
+
164
+ ```bash
165
+ sellable hermes profile bootstrap \
166
+ --profile acme \
167
+ --profiles-root /srv/hermes/profiles \
168
+ --workspace-id ws_acme \
169
+ --slack-bot-token "$SLACK_BOT_TOKEN" \
170
+ --slack-app-token "$SLACK_APP_TOKEN" \
171
+ --slack-home-channel C0ACME12345 \
172
+ --slack-home-channel-name sellable-acme \
173
+ --slack-allowed-users U0OPERATOR1 \
174
+ --slack-require-mention true
175
+ ```
176
+
177
+ When `--slack-home-channel` is supplied without
178
+ `--slack-allowed-channels`, bootstrap writes
179
+ `SLACK_ALLOWED_CHANNELS=<home-channel-id>` too. That fail-closes a customer
180
+ profile to the intended channel by default. Use
181
+ `--slack-allowed-channels C...,G...` only when a profile is deliberately allowed
182
+ to listen in multiple channels. Pass channel IDs, not `#channel-name`, and use
183
+ separate Slack bot/app tokens per customer profile when you need hard isolation
184
+ between concurrently listening Hermes profiles.
185
+
145
186
  Customer profiles should use customer-scoped Sellable credentials. A shared
146
187
  Sellable admin token can work for internal admin automation, but it is weaker
147
188
  isolation and should not be the default for customer profiles. After changing
@@ -171,7 +212,6 @@ source-scout agents.
171
212
  Use the same public entrypoints across supported hosts:
172
213
 
173
214
  - Claude Code: `/sellable:create-campaign`
174
- - Claude Code: `/sellable:find-leads`
175
215
  - Claude Code: `/sellable:create-ab-test`
176
216
  - Claude Code: `/sellable:create-evergreen-campaigns`
177
217
  - Claude Code: `/sellable:foundation`
@@ -180,7 +220,6 @@ Use the same public entrypoints across supported hosts:
180
220
  - Claude Code: `/sellable:refresh-sender-engagement`
181
221
  - Claude Code: `/sellable:refill-sends`
182
222
  - Codex: `$sellable:create-campaign`
183
- - Codex: `$sellable:find-leads`
184
223
  - Codex: `$sellable:create-ab-test`
185
224
  - Codex: `$sellable:create-evergreen-campaigns`
186
225
  - Codex: `$sellable:foundation`
@@ -189,7 +228,6 @@ Use the same public entrypoints across supported hosts:
189
228
  - Codex: `$sellable:refresh-sender-engagement`
190
229
  - Codex: `$sellable:refill-sends`
191
230
  - Hermes: `/sellable-create-campaign`
192
- - Hermes: `/sellable-find-leads`
193
231
  - Hermes: `/sellable-create-ab-test`
194
232
  - Hermes: `/sellable-create-evergreen-campaigns`
195
233
  - Hermes: `/sellable-foundation`
@@ -199,7 +237,6 @@ Use the same public entrypoints across supported hosts:
199
237
  - Hermes: `/sellable-refill-sends`
200
238
  - Codex Desktop plugin: `sellable@sellable`
201
239
  - Codex visible skill: `Sellable Create Campaign`
202
- - Codex visible skill: `Sellable Find Leads`
203
240
  - Codex visible skill: `Sellable Create A/B Test`
204
241
  - Codex visible skill: `Sellable Create Evergreen Campaigns`
205
242
  - Codex visible skill: `Sellable Foundation`
@@ -208,7 +245,6 @@ Use the same public entrypoints across supported hosts:
208
245
  - Codex visible skill: `Sellable Refresh Sender Engagement`
209
246
  - Codex visible skill: `Sellable Refill Sends`
210
247
  - Internal MCP workflow prompt: `create-campaign-v2`
211
- - Internal MCP workflow prompt: `find-leads-v2`
212
248
  - Internal MCP workflow prompt: `refill-sends-workflow`
213
249
  - Internal/backward-compatible memory prompt: `interview`
214
250
 
@@ -26,8 +26,8 @@
26
26
  "ownership": "message strategy, proof inventory, token rules, skeptical-prospect review, and selected winner only",
27
27
  "codex": {
28
28
  "description": "Message Drafting worker for campaign-backed template proposals after confirm_lead_list imports a non-empty bounded review batch.",
29
- "model": "gpt-5.5",
30
- "modelReasoningEffort": "xhigh",
29
+ "model": "gpt-5.6-sol",
30
+ "modelReasoningEffort": "high",
31
31
  "sandboxMode": "read-only",
32
32
  "nicknameCandidates": [
33
33
  "Message Drafting",