Help us improve
Share bugs, ideas, or general feedback.
From claude-for-msft-365-install
Walks an enterprise admin through configuring the Claude Office add-in to call their own cloud (Vertex, Bedrock, Foundry, or gateway), producing a customized manifest.xml for M365 deployment.
npx claudepluginhub changhochien/pi-financial-services --plugin claude-for-msft-365-installHow this command is triggered — by the user, by Claude, or both
Slash command
/claude-for-msft-365-install:setupThe summary Claude sees in its command listing — used to decide when to auto-load this command
# Claude in Office — Direct Cloud Setup You are walking an enterprise admin through configuring the Claude Office add-in to call their own cloud instead of Anthropic's API. The output is a customized `manifest.xml` they deploy via M365 Admin Center. **Before anything else:** the setup log lives at `~/Desktop/claude-for-msft-365-install-setup.md` (resolve `~` for their platform). If it exists, read it first — you may be resuming a prior run and can skip completed steps. Start a new `## Run — <timestamp>` section and append each command and its captured output (IDs, URLs) as you go. **Chec...
/setupWalks an enterprise admin through configuring the Claude Office add-in to call their own cloud (Vertex, Bedrock, Foundry, or gateway), producing a customized manifest.xml for M365 deployment.
/model-configInteractive wizard that detects installed AI providers and displays or guides configuration of models, routing, and cost for the Claude Octopus workflow system.
/setupConfigures TrueFoundry AI Gateway for the current project, including login verification and gateway routing setup.
/consensus-setupRuns interactive wizard to detect CLIs (kilo, codex, gemini, qwen), set OpenRouter key, and configure models/quorum for multi-model consensus reviews.
/setupInitializes or resumes project setup via interactive Q&A, creating conductor/ artifacts for product definition, guidelines, tech stack, workflow, and style guides.
/setupDetects and cleans up ghost installations of the claude-hud plugin by checking cache, registry, and temp files.
Share bugs, ideas, or general feedback.
You are walking an enterprise admin through configuring the Claude Office add-in
to call their own cloud instead of Anthropic's API. The output is a customized
manifest.xml they deploy via M365 Admin Center.
Before anything else: the setup log lives at
~/Desktop/claude-for-msft-365-install-setup.md (resolve ~ for their platform). If it
exists, read it first — you may be resuming a prior run and can skip completed
steps. Start a new ## Run — <timestamp> section and append each command and
its captured output (IDs, URLs) as you go.
Check for Node.js — Steps 4 and 6 shell out to node and npx. Run
node --version. If it's missing, ask before installing — it's their
machine. If they say yes, brew install node (mac) / winget install OpenJS.NodeJS
(win) / whatever their package manager is. If no, stop here.
When capturing values from the admin (IDs, URLs, secrets pasted back from a console) — don't use AskUserQuestion. That's a choice picker; they're holding a string. Just say "paste the Client ID when you have it" and read it from their next message. Use AskUserQuestion only for the actual branch points (gateway vs vertex, per-user vs org-wide).
Ask this first, because it's the thing admins get wrong: do you already run an LLM gateway (LiteLLM, Portkey, Kong, etc.)?
gateway. Even if the gateway routes to Vertex or Bedrock under
the hood — the add-in talks to your gateway, not to Google or AWS. You
just need the gateway URL.vertex or bedrock. The add-in authenticates directly to the
cloud provider. Pick where your infra lives.| Path | What it means | Provisioning | Manifest keys |
|---|---|---|---|
gateway | Add-in → your gateway → (whatever) | None | gateway_url (+ gateway_api_format if not /v1/messages) |
vertex | Add-in → Google Vertex AI, directly | Google OAuth client | gcp_project_id, gcp_region, google_client_id, google_client_secret |
bedrock | Add-in → AWS Bedrock, directly | IAM OIDC provider + role | aws_role_arn, aws_region |
foundry | Add-in → Azure AI Foundry, directly | Foundry resource + API key | azure_resource_name, azure_api_key |
Bedrock and per-user config (bootstrap endpoint or extension attrs) need
entra_sso=1 — the add-in acquires the user's Entra ID token to authenticate
those flows. See the Entra SSO section in manifest.
Ask: Excel/Word/PowerPoint, Outlook, or both? Outlook is a separate manifest and has one extra prerequisite.
If they're deploying Outlook:
bedrock
in Step 1, Outlook is off the table for now — generate only the office
manifest.graph_client_id needed) or
their own Entra app (capture graph_client_id).Branch to the matching section below.
Confirm with the admin:
us-east5)No gcloud command exists for this. Open the console link (substitute their
project ID), walk them through, they paste back the client ID and secret.
Open:
https://console.cloud.google.com/apis/credentials?project=<PROJECT_ID>→ Create Credentials → OAuth client ID
- Application type: Web application
- Name:
Claude for Office- Authorized redirect URI:
https://pivot.claude.ai/auth/callback→ Create → copy the Client ID and Client Secret
Enable the Vertex API while they're there:
gcloud services enable aiplatform.googleapis.com --project=<PROJECT_ID>
Capture: gcp_project_id, gcp_region, google_client_id, google_client_secret.
Continue to Step 3. Vertex uses Google OAuth, not Entra, so admin consent isn't needed unless you also opt into per-user config (in which case come back to Step 2 after deciding in Step 3).
Confirm with the admin:
us-east-1)az account show --query tenantId)aws CLI configured against the target accountThree aws iam calls. The trust policy's aud condition is the security
boundary — only tokens Azure minted for the Claude add-in can assume this role.
Substitute their tenant ID and region:
TENANT_ID="<their-azure-tenant-guid>"
CLAUDE_APP_ID="c2995f31-11e7-4882-b7a7-ef9def0a0266"
AWS_REGION="us-east-1"
ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
ISSUER="login.microsoftonline.com/${TENANT_ID}/v2.0"
# OIDC identity provider. Thumbprint is required by the API; AWS validates
# major IdPs via its own trust store, but the param can't be omitted.
THUMBPRINT=$(openssl s_client -servername login.microsoftonline.com \
-connect login.microsoftonline.com:443 </dev/null 2>/dev/null \
| openssl x509 -fingerprint -sha1 -noout | cut -d= -f2 | tr -d ':')
aws iam create-open-id-connect-provider \
--url "https://${ISSUER}" \
--client-id-list "${CLAUDE_APP_ID}" \
--thumbprint-list "${THUMBPRINT}"
PROVIDER_ARN="arn:aws:iam::${ACCOUNT}:oidc-provider/${ISSUER}"
# Role with trust policy gated on aud.
aws iam create-role --role-name ClaudeBedrockAccess \
--assume-role-policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Federated": "'"${PROVIDER_ARN}"'"},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {"'"${ISSUER}"':aud": "'"${CLAUDE_APP_ID}"'"}
}
}]
}'
# Bedrock invoke permissions.
aws iam put-role-policy --role-name ClaudeBedrockAccess \
--policy-name BedrockInvoke \
--policy-document '{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"],
"Resource": [
"arn:aws:bedrock:*::foundation-model/anthropic.*",
"arn:aws:bedrock:*:'"${ACCOUNT}"':inference-profile/us.anthropic.*"
]
}]
}'
echo "aws_role_arn: arn:aws:iam::${ACCOUNT}:role/ClaudeBedrockAccess"
If create-open-id-connect-provider errors with EntityAlreadyExists, a
provider for that issuer already exists — that's fine, the role will trust it.
The ARN is deterministic (arn:aws:iam::<account>:oidc-provider/<issuer>).
Capture: aws_role_arn, aws_region. Add entra_sso=1 when generating the
manifest — Bedrock needs the Entra ID token as the STS web identity.
Continue to Step 2.
No provisioning. Ask for the gateway base URL (LiteLLM, Portkey, etc) and the token. If the token varies per user, it goes in Step 5 instead of the manifest.
Capture: gateway_url, gateway_token.
API format. Ask: does the gateway expose the Anthropic /v1/messages API,
or is it a pass-through to Bedrock (/model/{id}/invoke…) or Vertex
(…:rawPredict)? Almost always Anthropic — LiteLLM/Portkey/Kong default to
it, and a unified /v1/messages route is the point of running a gateway. Only
set gateway_api_format to bedrock or vertex if the gateway is a thin
proxy that preserves the upstream wire format. If vertex, also capture
gcp_project_id (their GCP project) and gcp_region (typically us-east5) —
they're path segments in the URL the add-in constructs. Point gateway_url at
the pass-through path, e.g. https://litellm.acme.com/bedrock or
…/vertex_ai/v1.
Auth header scheme. The add-in sends the token as x-api-key: <token> by
default — this is what LiteLLM, Portkey, and Kong accept out of the box. If
your gateway expects Authorization: Bearer <token> instead (common for
custom/enterprise gateways), set gateway_auth_header=authorization. If
you're unsure, run the Step 6 smoke test with x-api-key
first — a 401 with "no Authorization header" in your gateway logs means you
need authorization.
Continue to Step 3. Gateway auth is token-based, not Entra, so admin consent isn't needed unless you also opt into per-user config (in which case come back to Step 2 after deciding in Step 3).
Confirm with the admin:
contoso-foundry
from https://contoso-foundry.services.ai.azure.com)Open the resource in the Azure Portal, then Keys and Endpoint → copy KEY 1. The add-in auto-detects which Claude models are deployed in the resource, so no model config is needed here.
Capture: azure_resource_name, azure_api_key.
Continue to Step 3. Foundry auth is key-based, not Entra, so admin consent isn't needed unless you also opt into per-user config (in which case come back to Step 2 after deciding in Step 3).
Only required when entra_sso=1 — that is, Bedrock (the Entra token is the
STS web identity) or per-user config via extension attrs/bootstrap. If neither
applies, skip to Step 3.
Read ${CLAUDE_PLUGIN_ROOT}/commands/consent.md and follow it.
The add-in reads per-user extension attributes first, falls back to manifest params. Any key can live at either layer. So the question is: of the values captured in Step 1, do any vary per user?
Ask concretely — don't make them map it themselves:
| Answer | Split |
|---|---|
| Nothing varies | Everything → manifest. Skip Step 5. |
| Unique per user (e.g. gateway token) | Unique key → Step 5, rest → manifest. |
Write the split into the setup log so Step 4 and Step 5 each know their subset.
Read ${CLAUDE_PLUGIN_ROOT}/commands/manifest.md and follow it with the
org-wide values from Step 3. Generate one file per host from Step 1b:
node "${CLAUDE_PLUGIN_ROOT}/scripts/build-manifest.mjs" office manifest.xml <key>=<value> ...
node "${CLAUDE_PLUGIN_ROOT}/scripts/build-manifest.mjs" outlook manifest-outlook.xml <key>=<value> ...
Then validate each:
npx -y office-addin-manifest validate manifest.xml
npx -y office-addin-manifest validate manifest-outlook.xml
Skip unless Step 3 routed something here. Otherwise pick a mechanism by what you're carrying:
| Carrying | Use | Read |
|---|---|---|
| A string or two — token, region | Extension attrs | ${CLAUDE_PLUGIN_ROOT}/commands/update-user-attrs.md |
mcp_servers, skills, anything structured | Bootstrap endpoint | ${CLAUDE_PLUGIN_ROOT}/commands/bootstrap.md |
Attrs are an az rest PATCH per user — less work, but flat strings ≤256 chars
only. Bootstrap is an HTTPS service you build — more work, no shape limits.
Before they deploy, confirm at least one of Claude Sonnet 4.5 or Claude Opus 4.5 (or newer) actually answers. A manifest that points at an unenabled model deploys fine and then fails silently at first user message.
Gateway: probe with a 1-token request. 200 means it works. 404 means the gateway doesn't route that model name — try the other, or ask them to check their gateway config. 429 means auth works but no quota on that model — try the other. 401/403 means the token is wrong, which is a Step 1 problem.
Pick the curl that matches gateway_api_format. (Windows: swap /dev/null
for NUL. If gateway_auth_header=x-api-key, swap the auth header line for
-H 'x-api-key: <token>'.)
gateway_api_format=anthropic (default):
curl -s -o /dev/null -w '%{http_code}\n' "<gateway_url>/v1/messages" \
-H 'content-type: application/json' -H 'authorization: Bearer <token>' \
-d '{"model":"claude-sonnet-4-5","max_tokens":1,"messages":[{"role":"user","content":"hi"}]}'
gateway_api_format=bedrock — model goes in the path, not the body:
curl -s -o /dev/null -w '%{http_code}\n' \
"<gateway_url>/model/anthropic.claude-sonnet-4-5-v1:0/invoke" \
-H 'content-type: application/json' -H 'authorization: Bearer <token>' \
-d '{"anthropic_version":"bedrock-2023-05-31","max_tokens":1,"messages":[{"role":"user","content":"hi"}]}'
gateway_api_format=vertex — model, project, and region all go in the path:
curl -s -o /dev/null -w '%{http_code}\n' \
"<gateway_url>/projects/<gcp_project_id>/locations/<gcp_region>/publishers/anthropic/models/claude-sonnet-4-5:rawPredict" \
-H 'content-type: application/json' -H 'authorization: Bearer <token>' \
-d '{"anthropic_version":"vertex-2023-10-16","max_tokens":1,"messages":[{"role":"user","content":"hi"}]}'
Vertex: model enablement is click-ops — the EULA accept has no API. Open the Model Garden page, confirm at least one model shows Enabled (not "Request access") for their region:
https://console.cloud.google.com/vertex-ai/publishers/anthropic?project=<PROJECT_ID>
If it says "Request access", they click through, accept terms, wait for enable. No API call until they confirm.
Bedrock: same constraint — model access grant has no API. Open the model access page, confirm at least one Claude 4.5+ model shows Access granted (not "Available to request"):
https://console.aws.amazon.com/bedrock/home?region=<aws_region>#/modelaccess
If it says "Available to request", they request, accept terms, wait for grant (usually minutes, sometimes longer).
Log the verified model name to the setup log. Don't proceed until you have a 200, a confirmed "Enabled", or a confirmed "Access granted" — whichever matches their path.
Walk them through the upload — there are a few screens, and the user-assignment one is a real decision.
Open:
https://admin.cloud.microsoft/?#/Settings/IntegratedApps→ Upload custom apps
- App type: Office Add-in
- Choose how: Upload manifest file (.xml) from device → select
manifest.xml- It validates on upload. If it errors here, Step 4's
npx office-addin-manifest validateshould have caught it — re-run that.
Users screen — the decision point:
→ Accept permissions → Finish deployment
Propagation to users takes up to 24 hours (usually much faster). The add-in appears under Home → Add-ins in Excel/Word/PowerPoint once it lands.
Append the final manifest path and the assignment scope to the setup log. Done.