@sellable/install
Version:
One-command installer for Sellable MCP in Claude Code, Codex, and Hermes
153 lines (118 loc) • 5.94 kB
Markdown
# Hermes Slack Profile Scoping
Use this when creating or updating customer Hermes profiles that need Slack
access.
## Default Rule
For Sellable-managed customer channels, use one dedicated Slack app/token pair
per active Hermes customer profile. Run native `hermes -p <profile> gateway run`
for that profile only. Do not run multiple active Hermes profile gateways
against the same `SLACK_APP_TOKEN`.
The customer's Slack app is bound to the exact Slack channel id and the
customer's profile-local Sellable MCP config. Customer profiles must not store
or read Sellable Admin MCP credentials, admin Slack app tokens, or sibling
profile config.
The 2026-07-06 Hostinger POC proved the native Hermes listener for the
`sellable-admin` profile with the existing `Sellable Reply Bot` app in
`#team-chat`: a human mention produced a new Hermes session and a threaded bot
reply. Treat that as proof that the gateway/listener path works for one owning
profile, not as approval for multiple active customer profiles sharing one app
token.
The same day, the `acme` profile reused the same redacted Slack token
fingerprints for an outbound-only smoke to `#sellable-acme` via:
```bash
hermes --profile acme send --to slack:C0BFERDV3N0 --subject '[Hermes acme smoke]' ...
```
That succeeded and is useful as an internal smoke test. It does not change the
inbound listener rule: each active customer profile needs its own native Slack
app token pair.
## Which Slack Values Are Enough
For outbound sends and ordinary Slack Web API calls, the important value is the
profile-local `SLACK_BOT_TOKEN`.
For native Hermes live listening through Slack Socket Mode, the profile also
needs `SLACK_APP_TOKEN`, an app-level `xapp-...` token with `connections:write`.
`SLACK_APP_ID`, `SLACK_CLIENT_ID`, `SLACK_CLIENT_SECRET`,
`SLACK_SIGNING_SECRET`, `SLACK_VERIFICATION_TOKEN`, `SLACK_TEAM_ID`, and
`SLACK_OPERATOR_EMAIL` do not replace `SLACK_APP_TOKEN`.
## Required Slack App Shape
Outbound Slack sends can work with fewer permissions. Native Hermes inbound
listening needs the Slack app itself to be configured for Socket Mode and event
delivery:
- Enable Socket Mode.
- Create an app-level token with `connections:write`.
- Install the bot with `app_mentions:read`, `channels:history`,
`channels:read`, `chat:write`, `groups:history`, `groups:read`,
`im:history`, `im:read`, `mpim:history`, `mpim:read`, and `users:read`.
- Subscribe bot events for `app_mention`, `message.channels`,
`message.groups`, `message.im`, and `message.mpim`.
- Reinstall the app after changing scopes or event subscriptions.
If the Slack app has `incoming-webhook`, Slack will ask for a webhook channel
during reinstall. Pick the profile home channel. That webhook selection does
not replace `SLACK_ALLOWED_CHANNELS`; keep the profile-local allowlist explicit.
## Profile Bootstrap Command
Use the Sellable installer profile bootstrap:
```bash
sellable hermes profile bootstrap \
--profile acme \
--profiles-root /srv/hermes/profiles \
--workspace-id ws_acme \
--workspace-name Acme \
--token-file /run/secrets/sellable-acme-token \
--slack-bot-token "$SLACK_BOT_TOKEN" \
--slack-app-token "$SLACK_APP_TOKEN" \
--slack-home-channel C0ACME12345 \
--slack-home-channel-name sellable-acme \
--slack-allowed-users U0OPERATOR1 \
--slack-require-mention true \
--json
```
If `--slack-home-channel` is supplied and `--slack-allowed-channels` is omitted,
the installer writes `SLACK_ALLOWED_CHANNELS=<home-channel-id>` automatically.
That makes the profile fail closed to the customer channel by default.
Use `--slack-allowed-channels C...,G...` only when a profile is intentionally
allowed to listen in more than one channel. Pass Slack IDs, not `#channel-name`
strings or wildcards.
## Resulting Profile Env
For the dedicated customer Slack app model, the profile-local `.env` should
contain only scoped Slack keys for that profile:
```env
SLACK_BOT_TOKEN=...
SLACK_APP_TOKEN=...
SLACK_HOME_CHANNEL=C0ACME12345
SLACK_HOME_CHANNEL_NAME=sellable-acme
SLACK_ALLOWED_CHANNELS=C0ACME12345
SLACK_ALLOWED_USERS=U0OPERATOR1
SLACK_REQUIRE_MENTION=true
```
Keep the file mode at `0600`. Do not copy raw tokens into planning docs, chat,
or committed artifacts. Record token fingerprints only.
The profile's Hermes MCP env must also include the profile-local Sellable
config, customer workspace lock, and fail-closed guard:
```yaml
SELLABLE_CONFIG_PATH: /srv/hermes/profiles/acme/sellable/config.json
SELLABLE_CONFIGS_DIR: /srv/hermes/profiles/acme/sellable/configs
SELLABLE_LOCK_WORKSPACE_ID: ws_acme
SELLABLE_REQUIRE_WORKSPACE_LOCK: "1"
```
`SELLABLE_REQUIRE_WORKSPACE_LOCK=1` means an unbound customer profile fails
closed before making Sellable API calls instead of falling back to shared or
admin config state. Only the `sellable-admin` profile should provision,
inspect, or repair other profiles.
## Verification
Run the installer and native profile UAT before publishing installer changes:
```bash
npm run test:unit -- tests/install-package/agent-preferences.test.ts
scripts/run-phase92-hermes-profile-bootstrap-uat.sh --mode local-temp
scripts/run-phase92-hermes-profile-bootstrap-uat.sh --mode linux-shaped
```
Expected proof:
- profile-local Sellable config paths remain authoritative
- generated profile `.env` has `SLACK_HOME_CHANNEL`
- generated profile `.env` has `SLACK_ALLOWED_CHANNELS`
- `acme` allowlist points at the `sellable-acme` fixture channel id
- redaction scan passes
## Current Phase 03 Status
Phase 03 proved the profile-scoped installer path, outbound Hermes send path,
and live Slack listener for the `sellable-admin` profile. Phase 03.1 now targets
dedicated native Slack apps per customer profile, profile-local Sellable MCP
locks, and fail-closed customer profile behavior so managed customer channels
can be onboarded through the VPS without local-only browser state, manual SSH
edits, or untracked processes.