---
name: onboard-client
description: "Plan and execute Sellable client onboarding after payment with Lightfield lifecycle tasks, Slack communication channels, workspace routing, and approval before mutation."
visibility: public
allowed-tools:
  - Read
  - Write
  - Edit
  - Bash
  - Glob
  - Grep
  - mcp__sellable-admin__admin_lightfield_search
  - mcp__sellable-admin__admin_lightfield_update_opportunity
  - mcp__sellable-admin__admin_lightfield_upsert_task
  - mcp__sellable-admin__admin_workspace_list
  - mcp__sellable-admin__admin_workspace_create
  - mcp__sellable-admin__admin_workspace_get
  - mcp__sellable-admin__admin_workspace_register
  - mcp__sellable-admin__admin_workspace_client_routing_set
  - mcp__sellable-admin__admin_workspace_archive
  - mcp__sellable-admin__admin_workspace_invite
  - mcp__sellable-admin__admin_workspace_slack_routing_get
  - mcp__sellable-admin__admin_workspace_slack_routing_set
  - mcp__sellable-admin__admin_hermes_onboarding_lifecycle
  - mcp__sellable-admin__set_active_workspace
  - mcp__sellable__get_active_workspace
  - mcp__sellable__list_workspaces
  - mcp__sellable__create_workspace
  - mcp__sellable__set_active_workspace
  - mcp__sellable__add_teammate
  - mcp__sellable__list_dnc_entries
  - mcp__sellable__load_csv_dnc_entries
  - mcp__codex_apps__google_calendar___search
  - mcp__codex_apps__google_calendar___read_event
  - mcp__codex_apps__google_calendar___batch_read_event
---

# Sellable Admin Onboard Client

Use this when Christian asks to onboard a newly paid client, for example
`onboard-client Dotwork`. The workflow must first produce a complete approval
packet. Do not mutate Slack, Sellable, Lightfield CRM, Gmail, or config state until
Christian approves that packet.

## Hermes Rehearsal Boundary

`onboard-client` remains the customer-facing onboarding workflow. It must not
be used for Hermes no-contact rehearsals. Those rehearsals use the separate
`onboard-client-v3-hermes` command, which is deliberately isolated from this
workflow's Slack Connect, workspace invite, customer-message, and routing
steps.

Do not invoke `admin_hermes_onboarding_lifecycle` with
`action: internal_onboarding_agent` from this skill. That legacy branch is not
the customer-safe bootstrap factory and must not be selected for a new run.

For the kickoff decision artifact, hand off once to
`$sellable-admin:onboarding-call` in preview-only mode. This reference never
authorizes `prepare`, `finalize`, or any Notion mutation.

## Runtime Paths

- Admin home: `{{adminHome}}`
- Admin repo: `{{adminRoot}}`
- Shared env wrapper: `{{envWrapper}}`
- Slack CLI wrapper: `{{slackPpCli}}` (also `{{codexSlackPpCli}}`)
- Config source of truth: `{{adminHome}}/config-state.json`, mirrored from `{{adminRoot}}/config-state.json` when setup runs

## Defaults

- Shared channel: `#sellable-{slug}`.
- Internal channels: `#sellable-{slug}-replies`, `#sellable-{slug}-followups`.
- External clients join only the shared channel unless Christian explicitly says otherwise.
- Replies and followups remain internal.
- Internal users/bot on all three channels:
  - Christian/admin: `U061L9Y48R1`
  - Christian from Dittto: `U0A8CBT1EUT`
  - Charls: `U07VCN4SLET`
  - Sellable Reply Bot: `U08CW83L2JF`
- Ops/admin Slack Connect participant on all three channels:
  - Shermeen Oad / VAM: `shermeen@thevamgroup.com`, known external Slack
    profile `U05L60L80SH`.
  - Add Shermeen with `conversations.inviteShared` by email to shared,
    replies, and followups. A normal `conversations.invite` may return
    `user_team_not_in_channel` until the VAM team is connected to that channel.
  - Treat Shermeen as Sellable ops/admin, not a client sender. Do not create a
    Sellable workspace invite or setup link for her unless Christian explicitly
    asks for that.
- Do not include Thomas by default.
- External invite list comes only from Christian's approved plan, not every deal contact.
- Slack operations use Printing Press Slack CLI with `--agent --json --data-source live`.
- Invoke the exact hydrated Slack CLI wrapper path listed under Runtime Paths.
  Never try a bare `slack-pp-cli`, raw binary, alternate env lookup, or second
  wrapper path first; the installed wrapper owns token loading.
- `admin@dittto.ai` is Slack user `U061L9Y48R1`; verify with `users lookup_by_email`
  only if challenged. Do not use the misspelled `admin@ditto.ai`.
- When Christian references a contact indirectly, such as "from our call
  yesterday", resolve the exact date from the current timezone, run a bounded
  Google Calendar search for that day plus the company/contact name, then read
  full event fields to recover attendee emails. Do not ask for the email until
  that bounded calendar lookup fails.
- Gmail is not part of default onboarding. Draft Gmail only when explicitly requested, and never send without approval.

## Phase 1: Read-Only Discovery

Resolve the input to a company name. Before any other discovery, define the
customer slug exactly once. It must match
`/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/`. Reuse that slug verbatim for the
Sellable workspace identity, Slack app (`Sellable Agent - {slug}`), channel
(`sellable-{slug}`), Hermes profile, config paths, and durable registry entry.
Do not derive a second spelling later in the run.

Then inspect current state without mutating anything:

- `config-state.json`: existing client entry, workspace ID, channel IDs, seats, contact, billing notes.
- Lightfield opportunity: `admin_lightfield_search`.
- Lightfield onboarding tasks: `admin_lightfield_search`.
- Lightfield client lifecycle tasks: `admin_lightfield_search`.
- Google Calendar, when the primary contact email is missing and Christian
  references a recent call: use the Calendar connector's bounded `_search` plus
  `_read_event`/`_batch_read_event` over the explicit date window, then choose
  the external attendee matching the company/contact. Record the source event
  title, date, and attendee email.
- Sellable workspaces: `admin_workspace_list`, then `admin_workspace_get` for likely matches.
- Slack channels:
  - `{{slackPpCli}} conversations --limit 1000 --types public_channel,private_channel --agent --json --data-source live`
  - Find exact and legacy names for shared/replies/followups.
  - For likely channels, inspect `conversations info`, members, and recent history.
  - For Slack Connect status, capture `is_shared`, `is_ext_shared`,
    `is_pending_ext_shared`, `pending_shared`, `pending_connected_team_ids`,
    and `properties.has_slack_connect_invite_created`.
- Workspace routing when a workspace ID exists: `admin_workspace_slack_routing_get`.
- Grain, Notion, or Gmail context only when available and relevant. Gmail reads are for context only.

Build an idempotent status map:

- Slack channels created/reused.
- Internal members present/missing.
- External Slack Connect invite state:
  - `accepted/active` when `is_ext_shared` or cross-org members are present.
  - `pending` when `is_pending_ext_shared`, `pending_shared`, or
    `pending_connected_team_ids` is non-empty.
  - `created_not_visible_as_pending` when
    `properties.has_slack_connect_invite_created` is true but pending/active
    fields are false/empty. This is still evidence the invite was created.
  - `missing/unverified` when only the generic `Import complete` output exists.
- Sellable workspace exists/missing.
- Workspace invite sent/accepted/missing for each approved external user.
- Reply routing points to `-replies`.
- Follow-up routing points to `-followups`.
- Onboarding message posted/missing.
- Lightfield onboarding tasks, Lightfield opportunity, Lightfield client lifecycle tasks, and config present/missing/stale.

## Phase 2: Approval Packet

Before any mutation, present a concise approval packet with exact values:

- Company, slug, contact, payment/seats, workspace assumption.
- Existing state and what will be skipped.
- External Slack Connect invites for the shared channel only.
- External Sellable workspace invites.
- Internal members/bot for all three channels.
- Channel names and any reused channel IDs.
- Exact onboarding Slack message.
- Exact setup-link message. For multi-seat deals, ask the primary contact for
  the remaining sender email addresses and LinkedIn profile URLs before
  creating extra setup links. Do not create links for non-sender attendees just
  because they were on a call.
- Routing plan: replies to `#sellable-{slug}-replies`, followups to `#sellable-{slug}-followups`.
- Hermes Slack native app plan:
  - customer slug, profile slug, and profile root
  - exact `SELLABLE_CONFIG_PATH` and `SELLABLE_CONFIGS_DIR`
  - token destination, token ID, and 16-hex fingerprint, never the token value
  - `SELLABLE_LOCK_WORKSPACE_ID=<customerWorkspaceId>` and
    `SELLABLE_REQUIRE_WORKSPACE_LOCK=1`
  - Sellable workspace ID/name
  - shared `sellable-{customerSlug}` channel ID/name and routing source
  - routing creation/update plan for shared, replies, and followups channels
  - dedicated Slack credential plan, generated manifest path/hash, app name
    `Sellable Agent - {slug}`, and app metadata path
  - enabled skills and response policy
  - per-surface post policies: customer is mention/thread gated and may post
    only through the approved flow; replies/followups are read-only metadata;
    home is draft-only metadata deferred to Phase 06
  - customer context packet source list, Hermes soul summary, and month-one ROI watchlist
  - exact first message copy and the receipt/readback verification steps
  This is required for managed Sellable channels so Hermes can use its built-in
  Slack gateway with a per-profile Slack app token pair.
- Customer invite policy: exactly one of `invite now`, `do not invite yet`, or
  `draft only`, covering both Slack Connect and Sellable workspace-member
  invites.
- Customer profile boundary: plain Sellable MCP is installed only with the
  workspace-scoped Sellable config/token for this customer and
  `SELLABLE_LOCK_WORKSPACE_ID=<customerWorkspaceId>` in the Hermes MCP server
  env. It must not receive Sellable Admin MCP tools, Slack app creation
  privileges, Slack app configuration tokens, or raw Slack bot/app tokens
  outside the profile-local secret/env target. It must not inspect
  `sellable-admin` or sibling profile config; only the `sellable-admin` profile
  may do cross-profile provisioning or repair.
- Future DB handoff: record that the eventual durable binding should store
  customer slug, workspace id, Hermes profile, Slack team/channel/app/bot ids,
  manifest path/hash, app metadata path, token fingerprints, secret refs,
  response policy, enabled flag, unique active binding constraints, and audit
  receipt paths. Never store raw Slack tokens in DB or config-state.
- Tracker/pipeline/client-ops/config updates.
- Verification steps.

Ask for explicit approval once. If Christian changes copy, invitees, seats,
contact, or channel names, regenerate the plan before executing. After approval,
call `mcp__sellable-admin__admin_hermes_onboarding_lifecycle` with
`action: authorize`. That one lifecycle authorization freezes customer slug,
company, invite policy, Slack team, allowed users, and `gpt-5.6-sol`, and
returns an opaque `lifecycleId`.

Every token, plan, apply, resume, verify, rebuild, rollback, or disable action
uses that opaque `lifecycleId`. Sellable Admin derives and validates child
authorization records internally for audit; operators never copy approval
hashes, packet paths, run hashes, or low-level tool arguments. Public results
must scrub those internal details. Workspace, channel, workspace lock, profile,
model, token destination, package, surface, and response-policy values must be
resolved by the lifecycle before mutation. `assigned-after-create` and
`explicitly-pending` remain forbidden in a mutation plan.

## Charls Verification

Charls verifies every row before the mutation sequence begins. Each row must be
`known`, `planned`, or `explicitly-pending`; there are no silent gaps.

- paid signal/source and the exact payment source-of-truth
- slug consistency across workspace, app, channel, profile, config, and registry
- package and seat count
- point-person name and email
- context evidence gathered-or-explicitly-unavailable for the email thread,
  LinkedIn thread, Grain/call notes, calendar context, payment source-of-truth,
  and handoff notes
- customer goals and month-one success definition
- sender names and emails, including an explicitly-pending sender matrix
- seat invite plan
- SalesNav status
- DNC/exclusions state
- routing source resolves to `sellable-{customerSlug}`
- shared, replies, and followups channel naming and IDs
- dedicated app/token listener model, never the production Sellable Reply Bot app
- replies and followups channels remain internal
- Slack Connect state
- Sellable workspace plus verified `admin@dittto.ai` access
- Sellable token file reference plus mandatory workspace lock inputs
- reply/follow-up routing target and shared-channel Hermes routing source
- Lightfield onboarding tasks, Lightfield client lifecycle tasks, Lightfield opportunity, and `config-state.json` rows
- customer profile target root and profile-local Sellable config path
- customer context packet and Hermes soul planned
- explicit customer invite policy: `invite now`, `do not invite yet`, or
  `draft only`

## No-Customer-Invite Test Mode

Use this 05B path when the approval packet selects `do not invite yet` or
`draft only`. It exercises the complete internal onboarding composition without
creating an external access side effect:

1. Create/reuse the Sellable workspace and verify its ID.
2. Add or verify `admin@dittto.ai` workspace access.
3. Create/reuse `sellable-{customerSlug}` plus the internal replies/followups
   channels.
4. Write and verify routing, including the shared Hermes routing source.
5. Prepare the profile-local Sellable token-file reference, fingerprint, and
   mandatory workspace-lock inputs.
6. Use `admin_hermes_onboarding_lifecycle` for authorize, plan, token mint, and
   apply; retain only the opaque `lifecycleId` as the operator handle.
7. Consume and verify the completed receipt.
8. Add only approved admin/internal data to the verified workspace.
9. Send the approved first onboarding message to the internal-only customer
   channel, or retain it as a draft when the packet says `draft only`.

This mode creates **NO customer Slack Connect invite**, **NO customer Sellable workspace-member invite**, and posts no setup link to any external person.
Point-person and sender invites happen only at a later explicit `invite now`
approval gate.

## Phase 3: Execute After Approval

Run only approved steps and skip anything already verified as done.

1. Create or reuse the Sellable workspace.
   - Resolve it first with `mcp__sellable__list_workspaces` or
     `admin_workspace_list`.
   - If missing, prefer `admin_workspace_create`; it atomically registers the
     exact created ID/name in the canonical Admin config-state used by Hermes.
     Use product `mcp__sellable__create_workspace` only when the Admin create
     path returns an explicit access blocker.
   - If an admin create/bootstrap attempt returns `403 Forbidden`, preserve that
     exact fallback semantics: use the product tool and verify by listing again.
   - If any path reports `pending`, keep the workspace state pending and resume
     verification. Do not assume it was created and do not invent an ID.
   - After create or reuse, call `admin_workspace_register` exactly once with
     the exact workspace ID. It verifies the product API readback and
     idempotently repairs canonical Admin state. Never edit `config-state.json`
     directly or trust a package-cache/repo-local mirror.
   - Confirm the exact active workspace with
     `mcp__sellable__get_active_workspace` before any access or routing work.

2. Ensure `admin@dittto.ai` has workspace access.
   - Read the workspace membership and pending invites first.
   - Reuse verified access. If missing, add or invite `admin@dittto.ai` through
     the product workspace context, then re-read membership or pending status.
   - Record `active`, `pending`, or an exact blocker. Do not treat an invitation
     response as accepted membership.

3. Create or reuse `#sellable-{slug}` plus the internal replies and followups
   channels. Prefer JSON import because some flag wrappers drop payload fields:

```bash
printf '%s\n' '{"name":"sellable-{slug}","is_private":false}' \
  | {{slackPpCli}} import conversations.create --input - --agent --json --data-source live
```

   Create/reuse `#sellable-{slug}-replies` and
   `#sellable-{slug}-followups` with the same exact-name lookup and JSON import
   pattern. Add the approved internal members/bot to all three channels with
   `conversations.invite`, then verify with `conversations members`; do not
   trust a generic import summary. If needed, use stdin plus required flags:

```bash
printf '%s\n' '{"channel":"C_CHANNEL","users":"U061L9Y48R1,U0A8CBT1EUT,U07VCN4SLET,U08CW83L2JF"}' \
  | {{slackPpCli}} conversations invite --channel C_CHANNEL --users U061L9Y48R1,U0A8CBT1EUT,U07VCN4SLET,U08CW83L2JF --stdin --agent --json --data-source live
```

   Send a Slack Connect invite by email only when the approval packet's invite
   policy names approved external emails for the shared channel:

```bash
printf '%s\n' '{"channel":"C_SHARED","emails":["client@example.com"]}' \
  | {{slackPpCli}} import conversations.inviteShared --input - --agent --json --data-source live
```

   Then verify with `conversations info`. Treat
   `properties.has_slack_connect_invite_created: true` as invite-created
   evidence even when `is_pending_ext_shared` remains false. External users
   often return `users_not_found` and do not appear in `members` until Slack
   Connect is accepted. Never claim accepted/active until Slack shows it.

   If Christian explicitly asks to add an external email to replies/followups,
   send Slack Connect invites by email to those channels too; do not use normal
   `conversations.invite` for an external email before the user exists locally.
   If Christian later asks to remove an external Slack Connect invite, first
   inspect `conversations info` for active/pending external share fields and use
   any exposed Slack Connect invite-list/revoke path if it returns an invite ID.
   If Slack only shows `has_slack_connect_invite_created: true` with no
   accepted/pending external share and `users lookup_by_email` returns
   `users_not_found`, record that exact state; do not claim the Slack invite was
   revoked unless Slack confirms it.

4. Write and verify workspace routing.
   - Use `admin_workspace_slack_routing_set` for the verified workspace.
   - `defaultChannelId/defaultChannelName` must be replies.
   - `followUpChannelId/followUpChannelName` must be followups.
   - Record the shared channel in `config-state.json` at
     `clients.{slug}.channels.shared`; that verified value is the Hermes routing
     source for `sellable-{slug}`.
   - If `admin_workspace_slack_routing_get` reports no
     `SlackWorkspaceIntegration` row, record routing as pending and do not
     fabricate routing, a channel ID, or a successful integration.
   - `routing-pending` is non-blocking for the dedicated native customer Slack
     app, customer-channel binding, isolated Hermes profile, and gateway.
     Completion receipts must report that native binding separately from the
     still-pending product reply/follow-up routing; never label the latter
     ready until the integration row exists and is uniquely resolved.
   - After all three exact channel IDs are verified, call
     `admin_workspace_client_routing_set` exactly once with the customer slug,
     company, registered workspace ID, and shared/replies/followups IDs. Require
     `registered: true` and `verified: true`. This tool is the only writer for
     lifecycle client routing; never edit config state directly.
   - Before lifecycle authorization or composition planning, require the
     successful `admin_workspace_register` and
     `admin_workspace_client_routing_set` receipts, then re-read
     `admin_workspace_list`, `admin_workspace_get`, and the stored shared-channel
     routing. Do not call lifecycle plan until the exact workspace ID is visible
     in canonical Admin state and `clients.{slug}.channels.shared` resolves to
     the exact channel. A newly created workspace/channel is not ready merely
     because its create call returned.

5. Prepare the profile-local Sellable user token and workspace lock inputs.
   - Follow `references/sellable-user-token-minting.md` before minting or
     writing any credential.
   - Before the approval checkpoint, call the same public lifecycle tool with
     `action: preflight` plus the verified Sellable `workspaceId`, and require
     its autonomous `preflight_smoke` receipt:
     the exact managed
     token was minted and disposed with `userActionRequired=false`, a sibling
     token remained authenticated, and workspace-lock authentication passed.
   - After approval, mint the real customer token only through
     `mcp__sellable-admin__admin_hermes_onboarding_lifecycle` with
     `action: token`, `mode: mint`, and the opaque `lifecycleId`. The broker
     supplies the exact internal authority automatically.
   - Re-verify that the product route requires
     `admin:hermes-customer-token-manage`, creates without revoking siblings,
     and never grants that capability to customer tokens. Gmail, magic links,
     SMS, and user auth tickets are not Sellable token-mint dependencies.
   - The approval packet and receipts contain only the token file reference,
     token ID, and 16-hex fingerprint, never the raw value.
   - Require the credential's server-side workspace binding plus exact
     `SELLABLE_LOCK_WORKSPACE_ID=<customerWorkspaceId>` and
     `SELLABLE_REQUIRE_WORKSPACE_LOCK=1` inputs before composition.

6. Invoke `mcp__sellable-admin__admin_hermes_onboarding_lifecycle` exactly once per lifecycle action.
   - Call read-only composition plan first, then call composition apply using
     the same opaque `lifecycleId`. Resume, verify, or disable through that same
     lifecycle; do not ask the operator for run identities or create a second
     lifecycle for the same authorized plan.
   - Construct `packageCandidates` exactly as the public tool schema declares:
     `sellableInstall`, `sellableMcp`, and `adminMcp` are `{package, sha256}`;
     `adminInstallSha` is the fourth 64-hex SHA-256. Do not guess aliases or
     probe alternate shapes.
   - The composition tool owns the named factory surface
     `$sellable-admin:hermes-slack-native-app` behind this call. The operator
     and this skill must not invoke factory internals or technical subcommands.
   - The authorized lifecycle must bind exact workspace/channel/team/profile/user
     identity, root-fallback `gpt-5.6-sol`, customer Sellable token-file ref,
     evidence target, and all four immutable package candidate hashes.
   - Apply/resume/rebuild/rollback/disable pass only the opaque lifecycle handle
     plus business inputs. The broker binds the saved plan and internally
     derives each child authorization. Plan/status/verify remain autonomous
     and read-only. Operators never copy technical approval identities.
   - Do not ask the operator to coordinate internal Slack CLI/API,
     Browserbase/Browser Use, Gmail/GWS, profile installer, Sellable installer,
     secret handoff, or native gateway subcommands.
   - Customer profiles contain only the dedicated Slack runtime secret pair,
     exact channel/user allowlists, current model object, root OAuth fallback,
     workspace-locked plain Sellable MCP, and the native s6 gateway. They must
     have no customer-local `auth.json`, Sellable Admin MCP, admin skills,
     provider keys, browser/Gmail credentials, provisioning credentials, or
     sibling data.

7. Consume and verify the completed factory receipt.
   - Require the persisted run ledger/receipt, exact workspace and channel
     authority, manifest and package hashes, token fingerprints, enabled
     surface policy, registry entry, and a green composition verify result.
   - Stop on a partial success, typed blocker, drift, mismatched identity, or
     missing receipt. Resume with the same `runId`; never bypass the receipt by
     editing profile files directly.
   - Render `references/customer-context-packet.md` into profile-root context
     and soul markdown owned by composition. Place both outside the factory
     drift-fingerprint set; never modify `config.yaml`, `.env`,
     `slack-app.json`, or `secrets/`.
   - The verify-after-write rule is mandatory: run
     `sellable-admin-install hermes customer bootstrap --mode verify --run-id <runId>`
     after both files are written and require no `external_state_drift` blocker
     before proceeding.

8. Post the approved first message to the shared channel.
   - Use the exact approved copy from the single Onboarding Message Template.
   - Do not post if the copy, target channel, customer invite policy, or
     per-surface posting policy differs from the approved packet.

9. Execute the approved customer Sellable workspace invite policy.
   - For `invite now`, prefer `mcp__sellable__add_teammate` on the active
     workspace with `role: MEMBER` and `redirectTo: /linkedin-accounts`; verify
     each active or pending result. Post setup links only in the shared channel.
   - For `do not invite yet` or `draft only`, create no external member invite
     and post no external setup link.
   - Use `admin_workspace_invite` only when product workspace context is not
     available; it may return `403` for product-created workspaces.
   - If an invite must be revoked and no MCP revoke tool exists, call
     `DELETE /api/v3/workspaces/invites/{inviteId}` with the workspace-scoped
     Sellable credential and `x-workspaceid`; verify `{"success":true}` before
     recording revoked.
10. Update Lightfield onboarding tasks.
11. Update Lightfield opportunity to the approved post-payment status.
12. Add or update Lightfield client lifecycle tasks using onboarding defaults.
13. Persist client/workspace/channel metadata only through the narrow
    `admin_workspace_register` and `admin_workspace_client_routing_set` canonical
    state store tools. Report unsupported billing metadata as pending; never
    edit or replace `config-state.json` directly.
14. Verify every ID/state and summarize completed vs pending.

Stop if a customer-facing message differs from the approved copy, a Slack
Connect invite returns an explicit admin/manual approval error, routing has
multiple integration rows, or required invite/contact data is missing. If
routing has no integration row, continue the rest of onboarding and record
`routing pending: connect Slack integration first`.

## Draft: Onboarding Momentum Follow-Through

Use this draft workflow when Christian asks to review an already-created client
onboarding channel and move the client forward, not to rebuild the full
onboarding packet. This is the lightweight follow-through loop that should
eventually power an onboarding-state reviewer across all pre-launch customers,
scheduled manually by Christian through automations when a client needs daily
movement.

Keep the same approval boundary: do not send customer-facing Slack/Gmail
messages without Christian approving the exact copy. Product/workspace actions
may be executed only when Christian explicitly asks for them and the target
workspace and inputs are verified.

1. Review the shared client channel with the Slack CLI.
   - Read recent history, channel info, members, and any CSV/file metadata.
   - Extract concrete onboarding inputs: sender emails, DNC/exclusion files,
     active-deal/customer lists, Sales Nav confirmation, existing outbound
     tools, install status, scheduling asks, and first-campaign direction.
   - Preserve the client's intended scope. If they say a file is full-domain
     DNC, treat it as DNC. If they say a file is specific active-deal people and
     not full-domain exclusion, do not convert those email domains into DNC.
2. Resolve and switch to the Sellable workspace.
   - Use `admin_workspace_list` to resolve the workspace ID by client name.
   - Use both `mcp__sellable-admin__set_active_workspace` and
     `mcp__sellable__set_active_workspace` when downstream tools use both admin
     and workspace-scoped Sellable APIs.
   - Report the previous and new active workspace in the working notes.
3. Turn submitted sender emails into setup links.
   - Use `mcp__sellable__add_teammate` with `role: MEMBER` and
     `redirectTo: /linkedin-accounts` so each invite link lands on LinkedIn
     account setup.
   - If a sender is already a member, do not create a duplicate invite. Mark the
     person as already in the workspace and give a direct next step to add their
     LinkedIn account.
   - Include invite expiration when the tool returns one.
4. Convert DNC artifacts into the real workspace DNC list.
   - Check the current DNC state with `mcp__sellable__list_dnc_entries`.
   - Preview with `mcp__sellable__load_csv_dnc_entries` using the exact active
     workspace, row count, valid count, invalid rows, duplicate count, and list
     name.
   - Get explicit preview confirmation before the confirmed write. The
     confirmation must name the workspace, list name, and counts.
   - Confirm with the preview token, then verify the final DNC count.
5. Interpret outbound-tool conflicts.
   - HubSpot-only is usually fine unless it is running LinkedIn actions through
     connected sender accounts.
   - Flag any LinkedIn automation, InMail sequences, connection request tools,
     or manual outbound already running on the same LinkedIn accounts before
     launch.
6. Draft the client-facing reply.
   - Lead with what is done: DNC loaded, files reviewed, sender links created,
     workspace membership status, or anything still pending.
   - Tell each sender to click their invite link, create an account, and add
     their LinkedIn account.
   - Ask for Sales Navigator confirmation and any outbound-tool conflicts that
     remain unclear.
   - For the launch/campaign-build call, ask the client to install Codex or
     Claude Code and run:

```text
curl -fsSL "https://app.sellable.dev/api/v2/cli/install" | sh
```

   - Include the scheduling link when appropriate:
     `https://calendly.com/dittto-christian/sellable-discovery-call`.
   - Ask for a rough first campaign description as a backup if install/setup is
     slow on the call: who to reach, lead source or signal, and the offer or
     reason they should reply. Say Sellable can tee it up before the meeting.
7. Daily momentum behavior for the future reviewer.
   - Assume Christian manually schedules the reviewer through automations for
     specific onboarding clients; do not create, modify, or schedule automations
     from this skill unless Christian explicitly asks.
   - If the client submitted new inputs, process what can be processed and draft
     an acknowledgement plus the next smallest ask.
   - If no new inputs arrived, draft a short bump focused on the specific
     blocker, not a generic onboarding checklist.
   - Deduplicate daily nudges by client/channel/blocker and never post the bump
     automatically until the sending policy for that future skill is approved.

## Onboarding Message Template

Use Slack mrkdwn. Keep it casual, concrete, and short. Use contractions. Say
rough direction is enough and Sellable will shape it into a campaign that should
work.

```text
Hey {first_name}, payment is all set. Excited to get started.

Here is what we need to get the first campaign moving:

- DNC/exclusions: companies, people, domains, competitors, customers, investors, or partners we should not contact.
- Sender emails: everyone who should send from Sellable.
- Sales Nav: confirm each sender has Sales Navigator active.
- Existing outbound tools: let us know if any sender is already running manual outbound, connection requests, InMails, or another sequencing tool.
- Codex: install Codex so we can collaborate async.
- Sellable MCP: run `curl -fsSL "https://app.sellable.dev/api/v2/cli/install" | sh`.

For the first campaign, rough direction is enough:

- who you want to reach
- the rough lead source or signal
- the offer or reason they should reply

We will shape that into a campaign that should work.
```

### First-Message Parity Rule

The fenced block above is the single canonical first-message copy. The Hermes
customer agent consumes that exact approved copy for its first customer-facing
message in `sellable-{customerSlug}`. A second onboarding-message template in
the Hermes agent, profile, context packet, or soul is forbidden. Change copy in
this source template first, re-approve it, and only then let Hermes consume it.

This message is the first customer-facing onboarding step. The agent uses it to
guide sender and SalesNav confirmation, Sellable setup invites,
DNC/exclusions, and campaign-call booking without inventing new copy.

## 05E Campaign Launch Walkthrough

After the first message, keep one onboarding state through launch:

1. Track sender/seat setup and Sellable membership.
2. Track SalesNav/LinkedIn setup for every approved sender.
3. Collect and verify DNC/exclusions.
4. Confirm calendar and reply/follow-up routing.
5. Confirm campaign-call readiness and book the call.
6. After the call, draft the campaign brief in Notion and attach the customer's
   desired outcome, month-one success definition, and ROI proof watchlist.
7. Get explicit brief/campaign approval, launch, and start sending through the
   normal campaign workflow.

This walkthrough is the canonical end-of-onboarding path for this milestone.
Keep what the customer wanted, what Sellable promised, expected meeting/ROI
proof points, and known risks attached to the customer profile context.

## Lightfield client lifecycle tasks Defaults

When adding a new onboarding client to Lightfield client lifecycle tasks:

- `health`: `Watch`
- `loadedLeads`: `0`
- `sent24h`: `0`
- `sent48h`: `0`
- `replyRate`: `n/a - onboarding`
- `pendingReplies`: `0`
- `daysUntilDry`: `0`
- `openQuestions`: pending DNC/exclusions, sender emails, Sales Nav confirmation, outbound-tool conflicts, Codex/MCP install, and rough first campaign idea
- `workspaceId`, `slackChannel`, and `replyChannel`: use verified IDs only

## Final Response

After execution, report:

- channels and IDs
- external Slack Connect invite state
- workspace ID and workspace invites
- routing verification
- tracker/pipeline/client-ops/config updates
- pending client items

Do not say Gmail was sent unless a Gmail send was explicitly approved and completed.
