---
name: setup-hermes-onboarding-agent
description: Plan, inspect, verify, rebuild, or disable an existing customer's workspace-locked Hermes onboarding agent through one opaque Sellable Admin lifecycle.
visibility: public
allowed-tools:
  - Read
  - mcp__sellable-admin__admin_hermes_onboarding_lifecycle
  - mcp__sellable-admin__admin_list_clients
  - mcp__sellable-admin__admin_workspace_list
  - mcp__sellable-admin__admin_workspace_get
  - mcp__sellable-admin__admin_workspace_archive
  - mcp__sellable-admin__admin_workspace_slack_routing_get
---

# Setup Hermes Onboarding Agent

Treat the lifecycle MCP as a deterministic safety primitive, not a scripted
decision engine. Before every apply/resume/rebuild/verify action, inspect live
status, ownership, concurrent-run state, and exact binding; choose the next
action from current evidence. After any failure, persist the observed
condition, diagnosis, revised strategy, and independent proof target. Never
repeat an unchanged failed strategy or encode failure meaning in a retry loop.

Use `mcp__sellable-admin__admin_hermes_onboarding_lifecycle` as the only
mutation interface in this skill: one authorization returns an opaque
`lifecycleId`; every later plan, token, apply, verify, rebuild, rollback, or
disable action uses only that ID plus the action's business inputs. Internal
child identities are generated, persisted, and checked by Sellable Admin.
By contract, operators never copy approval hashes, packet paths, or factory identities.
The same tool's `action: preflight` plus the verified Sellable `workspaceId`
runs and disposes the autonomous, server-bound credential smoke before
authorization.

For Christian-owned execution, `authorizedBy` is the configured owner identity
`christian@dittto.ai` or the Sellable Admin mailbox alias `admin@dittto.ai`.
Choose the identity already present in the onboarding context and authorize
once. Do not probe actor strings through retries.

## When to use

Use this skill for plan, rerun, status, verify, rebuild, disable, or registry
inspection of an existing customer binding. Use `onboard-client` for every
net-new customer mutation, including workspace and channel creation,
invitations, stored routing changes, and the initial lifecycle authorization.

The lifecycle broker may invoke the native factory after authorization.
Factory internals remain owned by `$sellable-admin:hermes-slack-native-app`;
do not render its stages as separate operator actions.

## Required inputs

Collect and validate all of the following before planning:

- the customer slug and company;
- the opaque `lifecycleId` returned by the authorization action;
- the requested composition mode: plan, apply, resume, status, verify,
  rebuild, rollback, or disable;
- a token-file reference containing only a mode-0600 VPS path, never token
  contents;
- four immutable package tarball and SHA-256 candidates from one sealed build
  cycle; refuse `@latest` and refuse mixed build cycles;
- explicit allowed Slack user IDs frozen by authorization;
- a VPS evidence target under `/opt/data`;
- the stored workspace and channel routing read through Sellable Admin.

The canonical profile is the customer slug under the approved profile root.
The canonical customer channel is `sellable-{customerSlug}`. The broker must
fail closed if stored routing does not resolve to that binding.

## Lifecycle authorization boundary

The human approves the customer-facing onboarding plan once. The authorization
action freezes the customer slug, company, invite policy, Slack team, allowed
users, and `gpt-5.6-sol`, then returns the opaque `lifecycleId`. That lifecycle
is the durable authority for later actions; no second operator transaction is
required for technical stages or teardown.

Run composition plan mode next. It must expose the target profile slug and profile root,
workspace, customer channel, routing write, per-surface post policies,
first-message behavior, package candidates, deterministic planned `runId`, and planned
`inputHash`. Plan mode produces zero external writes.

Sellable Admin internally derives mode-0600 child authorization records under
its owned mode-0700 admin state. Those records preserve internal audit
continuity and exact child binding while remaining private implementation
details. Public tool arguments and results contain neither copyable approval
identities nor internal record paths. Plan and status remain read-only. Verify
accepts only redacted live evidence collected by Hermes for the saved run and
completes the local verification ledger; it performs no new customer-facing
mutation.

## Response policy MVP

The agent watches only `sellable-{customerSlug}` through
`SLACK_ALLOWED_CHANNELS`. Customer replies are mention-gated, thread-gated,
and scheduled-check-gated. The first message may only come from the authorized
onboard-client flow. Replies, follow-ups, and home/control surfaces remain
registry metadata and cannot widen the allowed-channel list.

Home-surface behavior is explicitly deferred to Phase 06. Until then it is a
non-live metadata record with a draft-only post policy. Each registry surface
must record a `slashCommand` value or `n/a-MVP`.

## Apply, resume, status, verify, and rebuild

Call the lifecycle tool with `action: composition`, the opaque `lifecycleId`,
and the requested mode. Apply uses the immutable saved plan. Resume only the
same planned run and input identity. Status is read-only. Rebuild
uses the saved manifest, metadata, secret-bundle reference, and sealed package
candidates; it never substitutes current package tags.

An apply that completes through `gateway` and leaves `live_verification`
pending is ready for Hermes live UAT. That state is not a resumable factory
blocker: do not call resume, recreate composition, or reprovision Slack. Run the
positive, negative, MCP, and managed-restart checks through the existing direct
Browserbase CDP session, then call composition `verify` once with this redacted
`liveVerification` object:

The public apply/status result makes this explicit as
`factory.status: live_verification_pending`,
`factory.readyForLiveVerification: true`, and includes redacted
`factory.stages` plus `liveVerificationContext`. Treat that projection as the
authoritative handoff; do not wait for raw ledger access or reinterpret the
underlying `ledgerStatus: approved`.

```json
{
  "teamId": "T…",
  "channelId": "C…",
  "workspaceId": "workspace-id",
  "appId": "A…",
  "manifestSha256": "64-hex",
  "browserbaseSessionCount": 1,
  "userActionRequired": false,
  "allowedMention": { "replied": true, "sameThread": true, "latencySeconds": 1.2 },
  "negativeBoundaries": {
    "unrelatedChannelSilent": true,
    "disallowedUserSilent": true,
    "botAuthoredSilent": true,
    "adminSiblingInjectionSilent": true
  },
  "managedRestart": {
    "performed": true,
    "beforePid": 123,
    "afterPid": 456,
    "ownerCount": 1,
    "reply": { "replied": true, "sameThread": true, "latencySeconds": 1.1 }
  },
  "customerMcp": {
    "startupSeconds": 0.8,
    "toolCount": 42,
    "workspaceId": "workspace-id",
    "visibleWorkspaceCount": 1,
    "adminMcpPresent": false,
    "siblingInventoryFetched": false
  },
  "gatewayOwnerCount": 1,
  "redactionFindings": 0
}
```

The broker adds lifecycle, run, input, and customer identity itself. Verify
fails closed when a value is missing, out of range, or bound to another run.

Consume the returned factory receipt and registry readback as the authority for
workspace/channel/app/bot IDs, manifest hash, app metadata path, token
fingerprints, response policy, enabled state, and receipt paths. Internal child
authorization identities remain available for audit but are scrubbed from the
public response.

## Disable mode

`mode: disable` is the channel-binding off switch. On the same lifecycle, the
broker internally derives the teardown authority and makes exactly one factory `rollback` invocation
for the recorded run ID. Rollback is the factory's only
gateway-stop surface and performs a destructive full teardown: the run-owned
profile root and Slack app are removed.

After successful rollback, the broker flips the registry to `enabled: false`
and records `disabledAt` plus `disableReason`. It preserves registry metadata
including slug, workspace, channel, app ID, manifest hash, token fingerprints,
and receipt path as the durable record of what existed. The broker never manipulates s6 directly.
If the customer token remains live, disable revokes it internally after factory
rollback; do not revoke it early as a separate teardown step. Successful
rollback requires verified absence of the run-owned profile, gateway service,
runtime link, supervisor, and live run directory. Its mode-0600 audit receipt
is moved to the rollback-receipts root, so success never coexists with a live
run directory.

Re-enable with a NEW factory apply/rebuild from the preserved manifest,
metadata, and secret bundle; never resume the removed run. Non-destructive
pause/resume is deferred to Phase 07 multi-customer operations. Live
post-removal silence proof belongs to the Phase 05 teardown.
For synthetic/no-invite UAT only, archive the exact created workspace after
successful disable with `admin_workspace_archive`, then verify it appears only
when archived workspaces are requested. Never archive a real customer
workspace as a side effect of profile disable.
Prove the required post-removal silence while the internal Slack channel is
still readable, then archive the Slack channel and Sellable workspace. Reading
history after channel archival may return `not_in_channel` and cannot prove the
silence window.
For the pinned Printing Press Slack CLI, `conversations archive` must receive
the exact channel in both `--channel <id>` and the `--stdin` JSON body
`{"channel":"<id>"}`. Treat only the nested Slack response `data.ok=true` as
success; outer HTTP `success=true` with `data.ok=false` is a failed mutation.
Verify `conversations info --data-source live` reports `is_archived=true`
before accepting teardown. This CLI detail stays internal and is never a user
onboarding prerequisite.

## Fail-closed rules

Stop without a factory invocation or registry write when any of these typed
conditions occurs:

- `customer_routing_missing`: the client has no stored workspace/customer
  channel routing;
- `channel_conflict`: the requested channel differs from stored routing;
- `workspace_conflict`: the requested workspace differs from stored routing;
- `registry_binding_conflict`: the existing slug points at another binding;
- lifecycle identity or plan drift;
- package candidates are mutable, incomplete, or from mixed cycles;
- any secret value appears in arguments or receipts.

An approved routing migration is the only override for a same-customer stored
routing change. The migration must first update the onboard-client-owned
routing, then generate a new immutable plan inside the lifecycle. Never infer
or silently repair a workspace/channel binding in this skill.

## Deferrals and evidence

- Slack app/profile/gateway internals: defer to
  `$sellable-admin:hermes-slack-native-app`.
- Workspace/channel creation and invitations: defer to `onboard-client` and
  its explicit lifecycle authorization.
- Non-destructive fleet pause/resume: deferred to Phase 07.
- Home/control-surface execution: deferred to Phase 06.

Keep all execution and evidence on the VPS. Return redacted receipts,
fingerprints, lifecycle status, and evidence paths only. Never return secret
file contents or make a local browser, local filesystem, copied login code, or
manual VPS edit part of the production flow.
