claude-plugins

Deploying Typhoon firm-wide at Tempest

Tempest Capital, S.C. · Typhoon Excel Add-in (ITEM 1) Internal analytical work product — not investment, legal, tax, or accounting advice.

This is the step-by-step to take the add-in from this repo to every analyst’s Excel at Tempest (Windows desktop, Mac desktop, and Excel on the web) via Microsoft 365 Centralized Deployment.

Do the review fixes first. This guide assumes main is green — npm run typecheck, npm test, and npm run build all pass (see PLAN.md / README.md §7).


0. Architecture — two pieces deploy separately

Typhoon is two independently-deployed things. Getting firm-wide rollout right means doing both.

Piece What it is How it reaches analysts
A · Add-in (this folder) The ribbon tab + task-pane web app (dist/ + manifest.prod.xml) Preferred: M365 Centralized Deployment (§5). Firm-wide fallback when Integrated apps fails with “eligibility requirements”: Windows Trusted Catalog / network share via GPO or Intune (§5b).
B · Bridge (Azure Container Apps) Entra-authenticated API that owns the Claude key and returns governed format specs Preferred firm mode: deploy infra/typhoon-bridge/deploy.sh (§6a). Local typhoon serve is engineer-only (§6).

The add-in UI appears once A is deployed. In the firm build, commands light up only after MSAL Nested App Authentication succeeds against B. A dead or unauthorized bridge disables governed menus and leaves workbook cells untouched.

With a current bridge build, the taskpane auto-connects via loopback GET /handoff when typhoon serve is running — analysts do not paste the session token by hand. Intune should still auto-start typhoon serve at logon; the token handoff is then automatic.


1. Prerequisites


2. Build the add-in (produces dist/)

cd addin
npm ci                 # clean, lockfile-exact install
npm run typecheck      # tsc --noEmit (TypeScript strict)
npm test               # classifier parity vectors (FMG-1) — must pass
# Firm build variables (repository variables in CI):
export TYPHOON_BRIDGE_MODE=cloud
export TYPHOON_BRIDGE_BASE=https://typhoon-api.tempestcapital.com
export TYPHOON_ENTRA_CLIENT_ID=<application-client-guid>
export TYPHOON_ENTRA_TENANT_ID=<tenant-guid>
export TYPHOON_ENTRA_SCOPE=api://$TYPHOON_ENTRA_CLIENT_ID/access_as_user
export TYPHOON_BUILD_SHA=$(git rev-parse HEAD)
npm run build:cloud    # production bundle + CSP/config artifact gate

dist/ now contains taskpane.html, taskpane.js, assets/ (all 69 icons), and shortcuts.json. This is the whole web payload — there is no server code in A.


3. Host dist/ at the firm origin

Configure the Pages custom domain (for example typhoon.tempestcapital.com) and DNS before deployment. The workflow requires TYPHOON_HOST, TYPHOON_CUSTOM_DOMAIN, bridge URL and Entra values as repository variables; missing values fail the release.

One-time (repo admin): GitHub → Settings → Pages → Build and deployment → Source = GitHub Actions (not “Deploy from a branch”). The first merge of the workflow to main, or a manual Actions → addin-pages → Run workflow, publishes:

URL Purpose
https://typhoon.tempestcapital.com/ Firm landing page
https://typhoon.tempestcapital.com/typhoon/taskpane.html Task pane / Shared Runtime
https://typhoon.tempestcapital.com/typhoon/assets/icon-32.png Ribbon / tile icons
https://typhoon.tempestcapital.com/typhoon/manifest.xml Production manifest (M365 link)

Confirm with curl -I that taskpane.html, assets/icon-32.png, and manifest.xml return 200 before Centralized Deployment. Until Pages Source is switched to Actions, the site will keep serving the repo README and those paths will 404.

3b. Alternate hosts

Publish the contents of dist/ to the root of your HTTPS origin so that, for https://typhoon.tempestcapital.com:

Requirements: HTTPS with a trusted cert; long-lived caching is fine but cache-bust on update (see §8). No CORS config is needed for the add-in’s own assets (same origin). Example (Azure Static Web Apps):

npx @azure/static-web-apps-cli deploy ./dist --env production
# …or copy dist/* to your IIS/Blob/SharePoint site by your standard process.

4. Produce & validate the production manifest

The repo manifest points at https://localhost:3000 (dev). Rewrite it to the firm host — the <Id> GUID is the stable firm-wide app identity and is left unchanged:

# Firm-owned custom host (matches addin-pages repository variable):
npm run manifest:prod -- https://typhoon.tempestcapital.com/typhoon
#  → writes manifest.prod.xml
npx office-addin-manifest validate manifest.prod.xml

For a custom origin, pass that URL instead (no trailing slash). validate must report the manifest is valid. Keep manifest.prod.xml under source control (or your release store) — it is the artifact you upload in §5, and the same <Id> must be reused for every future update. The Pages workflow also publishes a hosted copy at /typhoon/manifest.xml.

Bump <Version> (e.g. 1.0.0.01.0.1.0) whenever you change the manifest (new commands, new host). Content-only changes (JS/HTML/CSS behind the same URLs) do not need a version bump — see §8.


5. Centralized Deployment — push to the firm

  1. Sign in to the Microsoft 365 admin centeradmin.microsoft.com.
  2. Settings → Integrated appsUpload custom apps.
  3. App type Office Add-in, then either:
    • Provide link to manifest filehttps://typhoon.tempestcapital.com/typhoon/manifest.xml, or
    • Upload manifest file (.xml) → choose local manifest.prod.xml.
  4. Assign users to the same analyst security group granted the Typhoon.User app role; widen that group rather than using an unrelated tenant-wide assignment.
  5. Review the manifest’s ReadWriteDocument permission (required for explicit ribbon formatting). NAA requests only Typhoon’s access_as_user API scope, not Graph or mailbox scopes. Accept and Deploy.
  6. Propagation: new deployments are typically visible within a few hours and up to 24 hours. Users see the Typhoon tab in Excel after relaunching; no per-user action is required.

That is the entire firm-wide step for A. (Excel on the web and desktop both pick it up from this one push.)


5b. Firm-wide fallback — Windows Trusted Catalog (when Integrated apps fails)

If admin.microsoft.com → Integrated apps ends with “Learn more about eligibility requirements” and Typhoon never appears in the app list, the tenant catalog write failed. That is a Microsoft 365 / Exchange eligibility problem (not the GitHub Pages host). Open a Microsoft support ticket with the correlation IDs from the pink banner, and use this path for Windows Excel desktop firm-wide in parallel.

What this does

Piece Where
Web payload (taskpane.html, icons, JS) Still GitHub Pages (…/typhoon/)
Manifest Copied to a UNC share readable by every analyst PC
Discovery in Excel Office Trusted Catalog registry (GPO / Intune / script)

Limits (Microsoft): Windows Excel desktop only. Not Mac, not Excel on the web. SharePoint app catalogs also do not work here — they ignore VersionOverrides (ribbon commands), which Typhoon requires.

IT steps (one afternoon)

  1. Create a firm file share, e.g. \\fs01\Software\TyphoonAddin, readable by Domain Computers / all analysts (write only for IT).
  2. On an admin PC (or Intune win32/script), run:
cd path\to\tempest-xlsx\addin\tools
# Pilot one user:
.\install-trusted-catalog.ps1 -CatalogShare '\\fs01\Software\TyphoonAddin' -Scope CurrentUser

# Firm-wide (local admin / SYSTEM — writes HKLM Policies):
.\install-trusted-catalog.ps1 -CatalogShare '\\fs01\Software\TyphoonAddin' -Scope AllUsers

The script downloads https://typhoon.tempestcapital.com/typhoon/manifest.xml into the share as TempestTyphoon.xml and registers the share as a Trusted Catalog.

  1. Push the same AllUsers script (or the equivalent registry) with Intune or GPO to every analyst Windows PC.
  2. Each user: fully quit Excel → reopen → Insert → Add-ins → More Add-ins → SHARED FOLDER (sometimes “MY ORGANIZATION”) → Tempest Typhoon → Add.
  3. Confirm the centrally deployed Azure bridge and Entra assignment (§6a); do not package typhoon serve.

Registry shape (if you prefer a raw .reg / Intune OMA-URI)

Under HKLM\SOFTWARE\Policies\Microsoft\Office\16.0\WEF\TrustedCatalogs\{a78def85-6545-41fb-be81-7cf950d3860d} (or HKCU\Software\Microsoft\Office\16.0\WEF\TrustedCatalogs\… for pilot):

Name Type Value
Id REG_SZ {a78def85-6545-41fb-be81-7cf950d3860d}
Url REG_SZ \\fs01\Software\TyphoonAddin (the folder, no trailing file)
Flags REG_DWORD 1

Still fix Centralized Deployment (Mac + Excel on the web)

Trusted Catalog does not cover Mac/web. Keep pursuing Integrated apps:

# After ExchangeOnlineManagement is imported (see ACTIVATION / support notes)
Get-OrganizationConfig | Format-List AppsForOfficeEnabled, EwsEnabled
# If AppsForOfficeEnabled is False:
Set-OrganizationConfig -AppsForOfficeEnabled:$true

Exchange admin center → Roles → Organization Management → Permissions → enable Org Custom Apps. File a Microsoft 365 support ticket with the eligibility correlation IDs. When CD works, you can retire the Trusted Catalog path.


6. Per-workstation bridge service (B)

Engineer/local mode runs through typhoon serve; do not distribute this path to firm analysts after cloud cutover:


6a. Firm cloud bridge + Entra SSO (ADR-0105 WP7) — preferred for firmwide

When Azure is available, analysts should not run typhoon serve. Deploy the cloud bridge and ship a cloud-mode add-in package:

  1. In Azure Cloud Shell, set tenant, analyst group, custom add-in origin and taskpane URL; run infra/typhoon-bridge/register-entra.sh. It creates the single-tenant NAA SPA/API, v2 access_as_user scope, group assignment and tenant admin consent.
  2. Set the environment variables required by infra/typhoon-bridge/deploy.sh, including ANTHROPIC_API_KEY; run it. The script deploys ACR, Key Vault, managed identity/RBAC, Redis, Log Analytics/alerts and ACA, builds the digest-pinned non-root image in ACR, and deploys two replicas with shared abuse controls.
  3. Configure GitHub repository variables listed in .github/workflows/addin-pages.yaml and the Pages custom domain/DNS. The release fails if cloud values, CSP, manifest version or bundle budget are wrong.
  4. Upload the hosted manifest through Integrated apps to the same analyst security group used by backend authorization.
  5. Pilot: Sign in to Tempest → AutoColor/Accounting → read-only metadata chat.

Engineers keep §6 local daemon (local mode). See the SOL review record in docs/research/2026-07-15_adr0105_wp7_panel_redteam.md.


7. Verify before you widen (pilot checklist)

Deploy to a pilot group first (§5 step 4) and confirm on a real Excel:


8. Updates, rollback, and housekeeping


One-page quick reference

# Build + verify
cd addin && npm ci && npm run typecheck && npm test && npm run build:cloud

# Host: merge to main (or Actions → addin-pages → Run workflow).
# One-time: Settings → Pages → Source = GitHub Actions.
# Confirm: https://typhoon.tempestcapital.com/typhoon/taskpane.html

# Production manifest (local copy; Pages also hosts /typhoon/manifest.xml)
npm run manifest:prod -- https://typhoon.tempestcapital.com/typhoon
npx office-addin-manifest validate manifest.prod.xml

# Push (preferred): admin.microsoft.com → Integrated apps → manifest URL → Deploy
# Fallback (Windows firm-wide when eligibility fails):
#   .\tools\install-trusted-catalog.ps1 -CatalogShare '\\fs01\Software\TyphoonAddin' -Scope AllUsers
#   → Intune/GPO that script; users Insert → Add-ins → SHARED FOLDER → Tempest Typhoon

# Engineer-local diagnostics only: `typhoon serve`