---
name: onboard-client-v3-hermes
description: "Run an explicitly approved, private, no-contact Hermes onboarding rehearsal through the proven customer bootstrap factory."
visibility: public
allowed-tools:
  - Read
  - Bash
  - Grep
---

# Onboard Client V3 Hermes

Use this command only for an explicitly approved no-contact rehearsal. It is a
separate path from `onboard-client`, not an extension of the customer-facing
onboarding workflow.

## Hard Boundary

For a rehearsal such as `station70test2`:

- Never invite, message, mention, reply to, or otherwise contact any customer
  or Station70 person.
- Never reuse, modify, join, or bind an existing customer Slack Connect,
  shared, replies, or follow-ups channel.
- Create exactly one newly named **private** internal test channel. It is not
  Slack Connect and it has no external members.
- Allow exactly one explicit internal operator; do not add customer users.
- Create no onboarding, setup-link, welcome, or test message. The dedicated
  app/profile may be created, but it must not initiate customer communication.
- Use the distinct test slug consistently for the private channel, app, and
  Hermes profile. The V3 command requires a terminal test marker: `test` or
  `test` followed by a positive integer such as `test2`.

Do not call the legacy `admin_hermes_onboarding_lifecycle` internal-agent
action. Do not use `onboard-client` for any V3 rehearsal. Do not use Slack MCP,
the Slack UI, local Chrome, or a customer token/app.

## Factory Command

The only mutation surface is the separate V3 command. It delegates to the
already-proven native customer bootstrap factory while binding the no-contact
rules into the immutable run identity:

```bash
sellable-admin-install onboard-client-v3-hermes \
  --mode <plan|apply|resume|status|verify|rebuild|rollback> \
  --no-contact \
  --customer-slug <distinct-slug-ending-in-test-or-test-number> \
  --company <test-label> \
  --team-id <explicit-team-id> \
  --workspace-mode reuse \
  --workspace-id <explicit-existing-workspace-id> \
  --channel-mode create \
  --channel-visibility private \
  --channel-name sellable-<test-slug>-onboarding \
  --internal-operator-slack-user-id <internal-operator-id> \
  --allowed-slack-user-ids <the-same-one-internal-operator-id> \
  --sellable-token-file <mode-0600-workspace-token-file> \
  --model gpt-5.6-sol \
  --evidence-target <restricted-evidence-directory> \
  --profiles-root /opt/data/profiles \
  --json
```

`plan` is read-only. `apply` requires the already-approved mutation authority
and `--approved`; it does not broaden the approved scope. `resume`, `status`,
`verify`, `rebuild`, and `rollback` require `--run-id` and `--no-contact`.
Use exact pinned Admin install, Admin MCP, Sellable install, and Sellable MCP
release candidates with their SHA-256 values for `apply`, `resume`, and
`rebuild`; never use `latest`.

The rehearsal token uses the separate `no_contact_rehearsal` authorization. It
is bound to the workspace lock, the planned private channel name, the exact V3
run, and one internal operator; it must not borrow a customer-onboarding or
preflight token identity.

After a read-only V3 plan, mint that bound token only through the
`admin_onboard_client_v3_hermes` broker with `action: "mint_token"` and
`approved: true`. Supply the exact plan `runId`, `inputHash`, workspace ID,
test slug, and internal operator ID. The broker owns its sealed approval
record; do not use `admin_hermes_customer_token` directly and do not invoke
the legacy lifecycle to obtain it.

The factory owns Browserbase direct CDP, email-code and authenticator-app TOTP
internally. It must not request an operator code, SMS, local browser session,
or raw Slack credential. Customer outreach remains disabled even if the
factory completes app/profile installation.

## Adaptive Browserbase Operator Lessons

The packaged Hermes LLM operator owns fragile Slack UI navigation. Deterministic
code supplies the exact identities, forbidden boundaries, secret handling, and
final API proofs; it must not encode a fixed button-by-button Slack dialog.

Route every step through the narrowest reliable surface. Use an authenticated
product or Slack API when it directly owns the operation and can be verified by
readback. Invoke the Browserbase LLM operator only for Slack admin surfaces that
have no safe supported API path, and give it an outcome, exact identities,
forbidden actions, current redacted gotchas, and a semantic CDP envelope rather
than a button script. A UI discovery must become a durable prompt lesson or an
API-first runtime rule before the next run; do not leave it as operator memory.

Seed every new run with these production-proven lessons:

- Re-inspect after every click because Slack replaces dialog DOM between steps.
- Wait for asynchronously rendered channel, app, and app-level-token lists;
  an initially empty list is not proof that no item exists.
- App-level-token generation is non-idempotent and each app allows at most ten.
  Inspect first, reuse the exact run-owned token, and deduplicate that exact
  name before generating anything new.
- Token revocation is two-stage. Select the exact run-owned token, choose
  Revoke, then confirm the dialog that says the token will be invalidated.
- Add a dedicated app to a private channel only through channel details and
  Integrations. Never use a message mention, people invite, or Slack Connect.
- Slack modals may render the exact app-row control after many unrelated page
  controls. Prioritize exact mission identity and modal controls before
  applying any interactive-ref cap.
- On the exact target private channel, the Integrations tab's exact `Add an
  App` control is a navigation-only step that may open the app picker. After
  the picker opens, never authorize an `Add`, `Install`, `Manage`, or `Remove`
  mutation from dialog-wide text. Its nearest app row must contain exactly the
  mission app name and no other Sellable app identity. The exact-channel URL
  guard supplies navigation scope, so this navigation-only
  control does not need local DOM ancestry to repeat `Integrations`.
  Newly created no-contact channels must reconcile to only the internal
  operator and exact run bot. After `users.info` positively identifies a
  surplus member as a stale Sellable test bot, remove only that bot with
  Slack's `conversations.kick` API and verify
  exact membership. The dedicated app's retained `groups:write` scope exists
  only for this private-channel membership reconciliation; never use it to
  invite a person. Never use the message composer or uninstall the app.
- Slack's channel Integrations popup can expose workspace-wide Manage, Remove,
  or Uninstall actions even though it was opened from one channel. Those are
  not channel-membership controls. Never click them to remove one bot, and do
  not spend another Browserbase retry rediscovering the same unsafe surface.
  Return the exact observed limitation to the deterministic controller, which
  must use `users.info` plus `conversations.kick` and live membership readback.
- A no-contact profile must set
  `platforms.slack.gateway_restart_notification: false` before its first
  gateway start. Hermes restart and shutdown notices are authored Slack
  messages and therefore fail zero-message proof even in an internal channel.
  Retrofit an already-running profile by reloading only its named s6 service
  from the silent config before the next graceful stop.
- A successful private-channel membership mission finishes in Slack Web.
  Return explicitly to the app's Basic Information page before reconciling its
  developer-console icon so the first successful attempt does not need a retry.
- Keep operator state and receipts mode `0600` and control directories mode
  `0700`, but make them owned by the Hermes profile runtime UID/GID before the
  operator starts. A root-invoked outer lifecycle must inherit the profile
  owner instead of leaving unreadable root-owned CDP state for Hermes.
- Treat changed labels or layouts as navigation evidence for the LLM to reason
  over, not as a reason to add another brittle selector.

Persist new redacted UI lessons in the run journal and include them in every
same-run retry. Return a blocker only for concrete platform, authentication,
permission, or safety evidence after safe adaptive paths are exhausted.
When a UI limitation has an already-supported deterministic API path, reroute
to that path in the same lifecycle rather than repeating the UI mission.

Printing Press mutation commands require both their exact identity flags and
the same request object through `--stdin`; flags alone can pass CLI validation
without reaching the Slack request body. Use that mutation form only for an
approved internal cleanup target, then prove the result with a live readback.

## Required Evidence

Before `apply`, record the exact workspace ID and the existing customer-channel
IDs as protected read-only references. The V3 approval packet must say:

- test slug and target private channel name
- workspace reuse only; no workspace member invitations
- exactly one internal operator allowlist member
- no customer Slack Connect, workspace, email, or message action
- exact package candidates and hashes
- no-contact approval wording

After the factory returns, use the Printing Press Slack CLI with
`--agent --json --data-source live` to verify the exact new channel is private,
not shared/external/shared-pending, has no customer member, and has no
messages. Re-read the protected existing customer channels to prove their
membership and history were unchanged. The V3 profile must remain
workspace-locked and must not send a greeting or any other proactive message.
For `--no-contact` verification, do not run mention/reply probes. Verify zero
messages, exact internal-operator plus dedicated-bot membership, no external or
shared state, protected-channel immutability, workspace isolation, and a
single-owner managed restart without posting anything.

Treat the new channel as a reserved verification surface from `plan` or
`apply` start until the packaged `verify` command seals the no-contact receipt.
Do not announce the channel as ready and do not invite manual message or reply
testing during that window. Immediately after `apply`, collect the zero-message,
membership, protected-channel, workspace-isolation, and silent managed-restart
proofs, then submit `verify` before any functional probe.

If a human or bot authors any message before the receipt is sealed, record the
typed `verification_window_contaminated` blocker. Preserve the message and run;
never delete authored content and never fabricate `messageCount: 0`. The run may
remain functional evidence, but it cannot satisfy strict no-contact proof. Plan
a fresh, explicitly approved, distinct test slug for the strict rerun. Mention
and reply testing is a separate post-verification activity and never substitutes
for the zero-message verifier.

If any requested operation would include a customer user, an existing customer
channel, a customer invite, or a message, stop without mutation and report the
boundary violation.
