From client-admin
Produce a pre-composed install command (Mac bash + Windows PowerShell one-liners) for a client admin to distribute to their team. The one-liner decrypts the shared credentials from the Claude Desktop marketplace sync. Use when the admin is ready to onboard employees. Never run this as an employee — the admin will send you a command.
How this skill is triggered — by the user, by Claude, or both
Slash command
/client-admin:generate-installerThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
*Last Edited: 2026-04-20*
Last Edited: 2026-04-20
Execute this skill directly. Do not enter plan mode. Do not expose detection logic, context rules, or internal derivation steps to the user. The user should see only: what you found, what you need from them, and the finished result.
/client-admin:generate-installer
/client-admin:generate-installer <slug> # master-repo-only: shortcut when you know which client
/client-admin:manage-credentials (encrypted credentials pushed; passphrase in hand) and are ready to distribute install commands to your team./client-admin:manage-credentials. Do that first: it encrypts credentials.env.age, pushes it to the harness repo, and gives you the passphrase that employees will need. The install command this skill emits is useless without that file synced through Claude Desktop.This skill emits install commands for the entire team. Its intended audience is client admins and consultants (coaching admins through the flow). Employees typing /client-admin:generate-installer out of curiosity is still a risk — the install block they'd get back references credentials the admin hasn't authorized them to distribute. Keep the gate.
Post-migration, the programmatic admin signals (gh auth, GITHUB_TOKEN rc-marker) are gone — nothing on an admin's machine is guaranteed to look different from an employee's. clients.json is the only automatic signal that survives. Admins typically run this from their own Claude Code session without clients.json, so the skill falls back to conversational confirmation. Single question keeps employee-refusal intact without blocking admins.
# Post-migration signals:
# - clients.json in $PWD → consultant (certain)
# - .claude-plugin/marketplace.json in $PWD → admin OR consultant
# (admin working inside their harness checkout, or consultant inside a client repo)
# - Neither present → unknown — ask the user
if [ -f clients.json ]; then
ROLE=consultant
elif [ -f .claude-plugin/marketplace.json ]; then
ROLE=admin_or_consultant
else
ROLE=unknown
fi
If ROLE=unknown, ask the user ONE question (no multi-step triage):
Quick check before I generate anything — who's running this: admin, consultant, or employee?
Employee refusal text:
This skill is for the admin who distributes the harness, not for team members who use it. It emits install commands that reference encrypted credentials employees aren't authorized to redistribute — your admin issues those.
If you're trying to install the harness on your own machine, ask your admin to send you the install command (they'll run
/client-admin:generate-installerthemselves and share the result).
Otherwise continue to the detection below.
Try these context rules in order; the first that succeeds wins.
Context A — Master repo (consultant): clients.json exists in $PWD.
if [ -f clients.json ]; then
jq -r '.clients[] | "\(.name)\t\(.repo)\t\(.status)"' clients.json
fi
If a slug arg was given, match it against .name; else ask the user which client. Display client names titlecased (e.g., test-client → "Test Client"), not raw slugs. Capture .repo.
Context B — Client repo (admin with the harness checked out): .claude-plugin/marketplace.json exists in $PWD.
if [ -f .claude-plugin/marketplace.json ]; then
jq -r '.name' .claude-plugin/marketplace.json
git config --get remote.origin.url
fi
Extract <org>/<repo> from the remote URL (strip https://github.com/ prefix and .git suffix).
Context C — Installed harness (admin's own machine): Read ~/.claude/plugins/known_marketplaces.json (the runtime registry — more reliable than settings.json which may be empty after a UI-based add).
jq -r 'to_entries[] | "\(.key)\t\(.value.source.url)"' ~/.claude/plugins/known_marketplaces.json
For each entry, check whether ~/.claude/plugins/marketplaces/<name>/credentials/ exists — only client harness repos have this directory; marketplace catalogs do not. Exclude entries without it. Display qualifying entries by the name field from .claude-plugin/marketplace.json titlecased, not the repo slug. If exactly one qualifies, use it automatically. If multiple, ask the user which.
If none of A/B/C produce a repo, tell the user: "I couldn't detect a client repo. Are you running this from your master repo, from inside a client's harness repo, or on a machine with the harness installed?"
CLIENT_REPO="<org>/<repo>" # from above
REPO_NAME="${CLIENT_REPO##*/}"
MARKETPLACE_NAME="${REPO_NAME%-claude-harness}"
MARKETPLACE_NAME="${MARKETPLACE_NAME%-harness}"
Must match what bootstrap.sh / bootstrap.ps1 / /onboard-client derive. If Context B surfaced a marketplace.json name that differs, the repo was onboarded before the Option C migration — flag it to the user and use the derived value anyway.
Execute these steps in order. Each step is a beat in the conversation — tell the user what's happening and what you need.
After running the detection logic above, tell the user what you found:
Generating install commands for [CLIENT_NAME] (
org/repo).
If detection failed or found multiple clients, ask the user to clarify. Keep it to one question.
Credentials are the only secret this skill touches. Before emitting anything, confirm the admin has actually encrypted + pushed them:
Have you run
/client-admin:manage-credentialsyet? It encryptscredentials.env.age, pushes it to the harness repo (so Claude Desktop can sync it to employee machines), and gives you the passphrase to send employees separately.
If they haven't run it, stop here and prompt them to do so before continuing.
If they have, ask how they plan to send the passphrase to employees. Default to the placeholder path:
How will you send the passphrase to your team?
1. 1Password, Bitwarden, or another secure channel (recommended) — I'll leave
<PASSPHRASE>in the output as a placeholder. Before you send the install message, swap in the real value. The passphrase never touches this chat.2. Slack direct message — Same as above: I leave a placeholder, you fill it in before sending. Just be aware that Slack DMs are stored on Slack's servers, so use a private DM rather than a channel.
3. Email — Same placeholder approach. Keep in mind that email is stored on mail servers in plaintext — use only as a last resort, and never CC anyone.
4. Paste it here (I'll include it in the output) — Paste your passphrase and I'll build it into the message ready to forward. Note: the passphrase will appear in this conversation, which Anthropic may retain in infrastructure logs. Fine for internal drills; avoid for real client credentials.
Wait for the user's choice. For options 1–3: use the <PASSPHRASE> marker in Step 3 and add an admin-facing reminder to substitute before sending. For option 4: ask for the passphrase value and substitute it in Step 3.
Substitute <CLIENT_NAME> and <ORG>/<REPO> always. For <PASSPHRASE>: substitute the real value if the admin pasted it (option 4); otherwise leave the literal <PASSPHRASE> marker.
Frame the output for the admin first. The admin needs to know the block below is what they forward to their team — NOT what they run themselves. Lead with one short framing sentence addressed to the admin, then output the forwardable block. Without the framing, admins read the recipient-facing "To install the <CLIENT_NAME>…" line and get confused about whose instructions they're looking at.
If using the placeholder path (options 1–3), add an admin-facing line above the passphrase block: "Before sending, replace <PASSPHRASE> with the real value — fill it in when you're drafting the outgoing message, not back into this chat."
Output format — emit in this exact structure. Each section is its own block so the admin can copy each part independently.
Admin framing (prose, not forwarded to employees):
Here's what to forward to your team. Copy each section in order — intro, then the command for their machine, then the after-install note. Send the passphrase separately via your chosen channel.
Intro — copy this first:
To install the <CLIENT_NAME> Claude Code harness:
Before running the command: add the `<ORG>/<REPO>` marketplace in Claude Desktop first and wait for the sync to complete. If the sync hasn't finished, the install will fail with a clear error message.
Mac / Linux — open Terminal, paste this line, press Enter:
bash <(curl -fsSL https://raw.githubusercontent.com/Palisades-Labs/claude-harness-installer/main/bootstrap.sh) --decrypt <ORG>/<REPO>
Windows — open PowerShell, paste all four lines below together, press Enter:
$env:DECRYPT_MODE='1'
$env:CLIENT_REPO='<ORG>/<REPO>'
Set-ExecutionPolicy -Scope Process Bypass -Force
iwr -useb https://raw.githubusercontent.com/Palisades-Labs/claude-harness-installer/main/bootstrap.ps1 | iex
After install — copy this last:
After the install completes, open a NEW terminal (or new PowerShell window) and run: claude
Then add the passphrase block for the admin to send via their chosen channel (separate message):
Send the passphrase below through your chosen secure channel — separately from the install message above:
<PASSPHRASE>The employee types or pastes it when prompted. It is not echoed and does not appear in their shell history.
Paste-robustness rule (critical): The Mac/Linux form is a single statement — bash <(curl ...) --decrypt <org>/<repo> has no inline env vars, so visual wrapping in Slack/email doesn't split interdependent lines. The Windows form still has three setup statements plus the iwr|iex call; keep each on its own line — do NOT collapse them into a single long line. Chat and email clients soft-wrap long commands and users' paste behavior often captures the visual wrap as real newlines, splitting the command into broken fragments. The multi-statement form is robust to wrap because each statement stands alone. Do not shorten the PowerShell block to a one-liner under any circumstance.
After the install block, print:
API key rotation
----------------
To add a new API key or rotate an existing one (Tavily, Avoma, or any other), run `/client-admin:manage-credentials`, update the key, and push. Employees pick up the new key on their next Claude Desktop marketplace sync — no new install command or passphrase distribution needed (as long as you keep the same passphrase).
If you rotate the passphrase itself, re-run `/client-admin:generate-installer` and redistribute both the install command and the new passphrase; employees re-run the one-liner to decrypt under the new passphrase.
bootstrap.sh and bootstrap.ps1 arg parsing in the claude-harness-installer repo. The current contract:
bootstrap.sh --decrypt <org>/<repo>bootstrap.ps1 -Decrypt -Repo <org>/<repo> (locally) OR $env:DECRYPT_MODE='1'; $env:CLIENT_REPO='<org>/<repo>'; iwr|iex (one-liner form; param() binding is skipped under iex so the script reads $env:DECRYPT_MODE and $env:CLIENT_REPO as fallbacks).
When either bootstrap changes its invocation, update the template above.bootstrap.sh, bootstrap.ps1, and /onboard-client. All four must derive marketplace names identically: basename(repo) with any trailing -claude-harness stripped, then any trailing -harness stripped (handles both naming conventions).jq — used on the operator's machine to parse clients.json and ~/.claude/settings.json during detection. Post-migration, bootstrap.sh / bootstrap.ps1 no longer install prereqs (they're decrypt-only), so jq must come from base tooling.Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub palisades-labs/marketplace-admin --plugin client-admin