@sellable/install 0.1.319 → 0.1.321

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.
@@ -1,169 +1,67 @@
1
1
  # Hermes Slack Profile Scoping
2
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
3
+ Sellable customer profiles use one dedicated native Slack app/token pair, one
4
+ workspace-locked plain Sellable MCP, and one native Hermes s6 gateway. There is
5
+ no shared dispatcher, route registry, listener fallback, or shared customer app
26
6
  token.
27
7
 
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:
8
+ The production Sellable Reply Bot remains separate HTTP-interactivity product
9
+ infrastructure. Keep Socket Mode off and keep its request URL at
10
+ `https://app.sellable.dev/api/v2/slack/interactions`.
56
11
 
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.
12
+ ## Public Boundary
65
13
 
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:
14
+ Customer onboarding is owned by the Sellable Admin native-app skill through one
15
+ public command:
73
16
 
74
17
  ```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
18
+ sellable-admin-install hermes customer bootstrap --mode <mode> [approved inputs]
88
19
  ```
89
20
 
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.
21
+ The operator uses read-only `plan`, then approved `apply`, and later
22
+ `resume|status|verify|rebuild|rollback` with the persisted `runId`. Do not ask
23
+ the operator to coordinate the public Sellable installer, Slack API/CLI,
24
+ cloud-browser, Gmail, profile, or gateway internals separately.
93
25
 
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.
26
+ The approval packet binds exact team/workspace/channel/profile/user identity,
27
+ customer Sellable token-file ref, `gpt-5.6-sol`, redacted evidence root, and the
28
+ exact tested Admin install/MCP and Sellable install/MCP candidates plus all four
29
+ SHA-256 values.
97
30
 
98
- ## Resulting Profile Env
31
+ ## Public Sellable Installer Role
99
32
 
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:
33
+ The Admin factory calls the pinned `@sellable/install` candidate internally and
34
+ passes the pinned `@sellable/mcp` candidate through `--mcp-package`. The public
35
+ installer writes profile-local Sellable config and Hermes MCP env with:
118
36
 
119
37
  ```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
38
+ SELLABLE_CONFIG_PATH: /opt/data/profiles/<customerSlug>/sellable/config.json
39
+ SELLABLE_CONFIGS_DIR: /opt/data/profiles/<customerSlug>/sellable/configs
40
+ SELLABLE_LOCK_WORKSPACE_ID: <approvedWorkspaceId>
123
41
  SELLABLE_REQUIRE_WORKSPACE_LOCK: "1"
124
42
  ```
125
43
 
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.
44
+ It does not create Slack apps, handle Slack tokens, install Admin MCP, or choose
45
+ the profile/workspace/channel from prompt text.
134
46
 
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
- ```
47
+ ## Customer Isolation
153
48
 
154
- Expected proof:
49
+ Customer profiles are blank-created. They contain:
155
50
 
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
51
+ - dedicated profile-local Slack runtime secrets in mode-`0600` storage
52
+ - exact channel and allowed-human ID allowlists
53
+ - customer-safe manifest with no slash/App Home/assistant/DM/MPIM surfaces
54
+ - the current `openai-codex` `gpt-5.6-sol` model object
55
+ - Hermes root OAuth fallback from `/opt/data/auth.json`
56
+ - pinned plain Sellable MCP locked to one approved workspace
57
+ - one profile-specific native s6 gateway
161
58
 
162
- ## Current Phase 03 Status
59
+ They never contain customer-local `auth.json`, provider pools, OpenRouter/raw
60
+ OpenAI keys, Sellable Admin MCP/admin skills, browser/Gmail/provisioning
61
+ credentials, TOTP material, or sibling data.
163
62
 
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.
63
+ Direct MCP proof before gateway start must show one intended active/visible
64
+ workspace, `siblingInventoryFetched=false`, and no Admin MCP. Slack acceptance
65
+ then requires real API/CLI, secret-file, s6 process, same-thread reply,
66
+ negative-isolation, restart, rollback, rebuild, and redaction receipts tied to
67
+ the immutable package hashes.
package/README.md CHANGED
@@ -83,120 +83,37 @@ Auth is stored once at:
83
83
  ~/.sellable/config.json
84
84
  ```
85
85
 
86
- ## Hermes Profile-Scoped Installs
86
+ ## Hermes Customer Profiles
87
87
 
88
- For a single local Hermes profile, point Sellable auth and memory at the profile
89
- instead of the global `~/.sellable/config.json`:
88
+ Customer onboarding is owned by the Sellable Admin native customer bootstrap:
90
89
 
91
90
  ```bash
92
- profile="$HOME/.hermes/profiles/acme"
93
- sellable --host hermes \
94
- --sellable-config-path "$profile/sellable/config.json" \
95
- --sellable-configs-dir "$profile/sellable/configs"
91
+ sellable-admin-install hermes customer bootstrap --mode <mode> [approved inputs]
96
92
  ```
97
93
 
98
- That writes `SELLABLE_CONFIG_PATH` and `SELLABLE_CONFIGS_DIR` into
99
- `mcp_servers.sellable.env`, so first-run login, `get_auth_status`, workspace
100
- switches, and Sellable memory all use the same profile-local files. Hosted MCP
101
- mode does not receive local filesystem paths.
94
+ That command is the sole operator-facing interface. It calls the exact pinned
95
+ `@sellable/install` tarball internally and passes the exact pinned
96
+ `@sellable/mcp` tarball through `--mcp-package`. Do not ask an operator to run
97
+ the public installer, supply Slack tokens in argv, edit profile files, or manage
98
+ the gateway as separate onboarding steps.
102
99
 
103
- For zero-shot local or Hostinger/Linux VPS bootstrap, use the profile command:
100
+ The internal profile stage writes profile-local Sellable paths and the exact
101
+ workspace boundary:
104
102
 
105
- ```bash
106
- sellable hermes profile bootstrap \
107
- --profile acme \
108
- --profiles-root /srv/hermes/profiles \
109
- --workspace-id ws_acme \
110
- --workspace-name Acme \
111
- --token-file /run/secrets/sellable-acme-token \
112
- --json
113
- ```
114
-
115
- It creates:
116
-
117
- ```text
118
- /srv/hermes/profiles/acme/config.yaml
119
- /srv/hermes/profiles/acme/sellable/config.json
120
- /srv/hermes/profiles/acme/sellable/configs/
121
- /srv/hermes/profiles/acme/skills/sellable/
122
- /srv/hermes/profiles/acme/.env # only when Slack token inputs are supplied
103
+ ```yaml
104
+ SELLABLE_CONFIG_PATH: /opt/data/profiles/<customerSlug>/sellable/config.json
105
+ SELLABLE_CONFIGS_DIR: /opt/data/profiles/<customerSlug>/sellable/configs
106
+ SELLABLE_LOCK_WORKSPACE_ID: <approvedWorkspaceId>
107
+ SELLABLE_REQUIRE_WORKSPACE_LOCK: "1"
123
108
  ```
124
109
 
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.
110
+ The locked MCP requests only the approved workspace, blocks workspace switching
111
+ and creation, and reports `siblingInventoryFetched=false`. The customer profile
112
+ must contain no Admin MCP, admin token, customer-local OAuth, or sibling config.
132
113
 
133
114
  See [`HERMES-SLACK-PROFILE-SCOPING.md`](./HERMES-SLACK-PROFILE-SCOPING.md) for
134
- the customer Slack isolation contract and Socket Mode token requirements.
135
-
136
- If no token is supplied, bootstrap still creates a pending
137
- `sellable/config.json` so the profile path is concrete from the first MCP
138
- launch. Finish auth with:
139
-
140
- ```bash
141
- sellable auth set <token> --workspace-id <workspace_id> \
142
- --sellable-config-path /srv/hermes/profiles/acme/sellable/config.json
143
- ```
144
-
145
- Slack Socket Mode tokens can be written profile-locally:
146
-
147
- ```bash
148
- sellable hermes profile bootstrap \
149
- --profile acme \
150
- --profiles-root /srv/hermes/profiles \
151
- --workspace-id ws_acme \
152
- --slack-bot-token "$SLACK_BOT_TOKEN" \
153
- --slack-app-token "$SLACK_APP_TOKEN"
154
- ```
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
-
186
- Customer profiles should use customer-scoped Sellable credentials. A shared
187
- Sellable admin token can work for internal admin automation, but it is weaker
188
- isolation and should not be the default for customer profiles. After changing
189
- Hermes profile config, restart the gateway/session or run `/reload-mcp` and
190
- `/reload-skills`.
191
-
192
- Validate the active profile with the same path inputs:
193
-
194
- ```bash
195
- SELLABLE_CONFIG_PATH=/srv/hermes/profiles/acme/sellable/config.json \
196
- SELLABLE_CONFIGS_DIR=/srv/hermes/profiles/acme/sellable/configs \
197
- sellable --verify-only --host hermes --json \
198
- --artifact /srv/hermes/profiles/acme/sellable/verify-runtime.json
199
- ```
115
+ the dedicated native Slack app, root OAuth fallback, immutable package, s6
116
+ gateway, rebuild, and live UAT contract.
200
117
 
201
118
  Claude Code, Codex, and Hermes are configured to launch the same packaged MCP server. The
202
119
  installer also writes Sellable agent definitions from the packaged `agents/`
@@ -213,26 +213,19 @@ Auth:
213
213
  also pass --sellable-config-path or set SELLABLE_CONFIG_PATH so auth and MCP
214
214
  runtime use the same profile-local config file.
215
215
 
216
- Hermes profile bootstrap:
217
- sellable hermes profile bootstrap --profile acme --profiles-root /srv/hermes/profiles --workspace-id ws_acme --token-file /run/secrets/sellable-token --json
218
- sellable hermes profile bootstrap --profile-root "$HOME/.hermes/profiles/acme" --workspace-id ws_acme --json
219
-
220
- Bootstrap writes <profileRoot>/config.yaml, <profileRoot>/sellable/config.json,
221
- <profileRoot>/sellable/configs, Sellable Hermes skills, and optional
222
- <profileRoot>/.env Slack token and channel-scope keys. For customer profiles,
223
- pass --slack-home-channel; bootstrap defaults SLACK_ALLOWED_CHANNELS to that
224
- exact channel id unless --slack-allowed-channels is supplied. Use
225
- customer-scoped Sellable credentials and customer-scoped Slack credentials for
226
- customer profiles; shared admin tokens are weaker isolation and should remain
227
- internal-only. Bootstrap writes SELLABLE_REQUIRE_WORKSPACE_LOCK=1 whenever a
228
- workspace id is supplied, so a customer profile fails closed if the workspace
229
- lock is later removed or not yet provisioned.
230
-
231
- Hermes shared Slack dispatcher:
232
- Shared listener setup and route-registry validation are internal Sellable
233
- Admin responsibilities. This customer-facing installer only bootstraps a
234
- profile-local Sellable runtime after Sellable Admin provisions the profile
235
- and dispatcher route.
216
+ Hermes customer profile stage:
217
+ Managed customer onboarding uses only:
218
+ sellable-admin-install hermes customer bootstrap --mode <mode> [approved inputs]
219
+
220
+ The Admin state machine invokes this package's profile bootstrap internally
221
+ with exact token-file, workspace-lock, profile-root, and --mcp-package inputs.
222
+ Operators must not use the low-level profile command to coordinate Slack,
223
+ profile, or gateway onboarding manually. Customer profiles use root Codex
224
+ OAuth fallback and contain no local auth.json, provider pool, or Admin MCP.
225
+
226
+ Hermes customer Slack runtime:
227
+ Each customer profile uses its own dedicated native Slack app and gateway.
228
+ Sellable Admin owns the single resumable customer bootstrap interface.
236
229
  `;
237
230
  }
238
231
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/install",
3
- "version": "0.1.319",
3
+ "version": "0.1.321",
4
4
  "type": "module",
5
5
  "description": "One-command installer for Sellable MCP in Claude Code, Codex, and Hermes",
6
6
  "bin": {
@@ -276,10 +276,6 @@ need raw proof, call the read-only `get_scheduler_fill_capacity` query for the
276
276
  same sender/action/date; it tells the MCP how many cells the product scheduler
277
277
  will try to place and does not import, approve, schedule, refresh credits, or
278
278
  mutate.
279
- Treat `rollingWeeklyInvite.capacityFreedDuringWindow:true` as proof that
280
- rolling-weekly capacity frees later in the send window and remains schedulable;
281
- use its timing fields instead of treating the window-start gate as a permanent
282
- full-day blocker.
283
279
  When the refill loop has ready rows and needs scheduler pickup now, use
284
280
  `run_scheduler_sweep` with the same explicit `workspaceId`; it can place cells
285
281
  within existing scheduler gates and returns the receipt, but it never sends or