Files
zeekay 6bbca15a5d Publish the Office and Outlook add-ins as sites
hanzo.yml declares two sites, office and outlook, built from their dist/
on every push to main and served at office.hanzo.ai and outlook.hanzo.ai
from the Sites plane. Each build stamps its own host into manifest.xml,
so the published manifest is the one to sideload or submit. The office
README records why the Copilot declarative agent is not a single
manifest here and the steps that make it one.
2026-09-30 14:56:24 -07:00

5.7 KiB

Hanzo AI for Microsoft Office

A task-pane add-in that puts Hanzo AI inside Word, Excel, and PowerPoint β€” desktop and Office on the web. Select text or a range, open the Hanzo pane from the Home tab, ask, and insert the result. This is the surface a non-developer (a lawyer drafting in Word, an analyst in Excel) actually uses β€” distinct from the browser extension and the IDE extensions.

It reuses the same backend as everything else Hanzo: model calls go through api.hanzo.ai/v1 (OpenAI-compatible), sign-in is Hanzo IAM (hanzo.id, authorization-code + PKCE, HIP-0111). No new API surface.

What it does

  • Word β€” read the selection; draft, rewrite, summarize, or answer; insert after or replace the selection.
  • Excel β€” read the selected range (as TSV); analyze/transform; write the result down a column from the selection.
  • PowerPoint β€” read/replace the selected text on a slide.

The engine of the add-in is small, pure, and unit-tested (tests/): the chat request/response shaping (chat.ts), the PKCE + authorize URL (pkce.ts, verified against the RFC 7636 test vector), the Excel range↔text helpers (host.ts), and the endpoint contract (config.ts). The Office.js glue is thin.

Build

pnpm --filter @hanzo/office-addin build      # production (base https://office.hanzo.ai)
pnpm --filter @hanzo/office-addin test        # vitest

The build stamps the hosting base URL into dist/manifest.xml. Office loads the task pane from an HTTPS origin declared in the manifest; the same origin serves auth-callback.html (the IAM redirect target, which must be registered on the hanzo-office IAM client). Override the base for local dev:

HANZO_OFFICE_BASE=https://localhost:3000 pnpm --filter @hanzo/office-addin build

Try it (sideload β€” no store needed)

The add-in is not on AppSource yet, but sideloading gives a lawyer immediate use inside their own Office:

  • Office on the web: open Word/Excel on the web β†’ Insert β†’ Add-ins β†’ Upload My Add-in β†’ pick dist/manifest.xml. (dist/ must be served at the base URL over HTTPS.)
  • Windows / Mac desktop: put dist/manifest.xml in a shared-folder catalog (or use office-addin-debugging), then Home β†’ Add-ins β†’ Shared Folder.
  • Whole firm: an M365 admin deploys manifest.xml org-wide from the Microsoft 365 admin center β†’ Integrated apps β€” every user gets the Hanzo button with no per-person install.

Hosting

CI publishes dist/ on every push to main: the repo's hanzo.yml sites: entry office builds it and uploads it to the Sites plane (s3://hanzo-sites/hanzo/office), and universe charts/app/values/hanzo/static-sites.yaml routes office.hanzo.ai to that prefix β€” no pod. So https://office.hanzo.ai/manifest.xml is always the manifest of main, stamped for that host. The Outlook add-in (../outlook) ships the same way at outlook.hanzo.ai.

Sign-in is the hanzo-office IAM client (type: spa, public, PKCE), declared in universe charts/app/values/hanzo/iam-provision.yaml with the redirects https://office.hanzo.ai/auth-callback.html and https://outlook.hanzo.ai/auth-callback.html.

Publish (AppSource β€” public listing)

dist/manifest.xml is a valid, submittable manifest (verified by office-addin-manifest validate). To list publicly, submit https://office.hanzo.ai/manifest.xml through Microsoft Partner Center β†’ Marketplace offers β†’ Office add-in (needs a Partner Center account and Microsoft's validation pass).

Copilot (declarative agent) β€” not in this repo yet

A Microsoft 365 unified manifest (manifest.json) could carry this add-in and declare Hanzo as a Copilot declarative agent, but not as one small file: an agent that answers with Hanzo must call api.hanzo.ai through an API plugin, otherwise Copilot answers with Microsoft's model. That is five files plus an OAuth registration held by Microsoft. The steps:

  1. Convert the XML manifest: npx office-addin-manifest-converter convert dist/manifest.xml writes manifest.json (unified manifest) and its color/outline icons.
  2. In manifest.json (manifestVersion 1.19 or later) add "copilotAgents": { "declarativeAgents": [{ "id": "hanzo", "file": "declarativeAgent.json" }] }.
  3. declarativeAgent.json (declarative agent schema v1.x): name "Hanzo AI", description, instructions, and "actions": [{ "id": "hanzo", "file": "hanzo-plugin.json" }].
  4. hanzo-plugin.json (API plugin schema v2.x): one OpenApi runtime with "spec": { "url": "openapi.yaml" }, "run_for_functions": ["chat"] and "auth": { "type": "OAuthPluginVault", "reference_id": "<step 6>" }.
  5. openapi.yaml: server https://api.hanzo.ai, one operation POST /v1/chat/completions with operationId: chat.
  6. Declare an IAM client hanzo-copilot in universe iam-provision.yaml (type: confidential, redirect https://teams.microsoft.com/api/platform/v1.0/oAuthRedirect), seal its secret in KMS, then in the Teams Developer Portal β†’ Tools β†’ OAuth client registration register it: authorization endpoint https://hanzo.id/v1/iam/oauth/authorize, token and refresh endpoints https://api.hanzo.ai/v1/iam/oauth/token, scope openid profile email offline_access, base URL https://api.hanzo.ai. The registration ID it returns is step 4's reference_id.
  7. Zip manifest.json, the icons and the three agent files; upload the zip in the Microsoft 365 admin center β†’ Settings β†’ Integrated apps (users need a Microsoft 365 Copilot license).

Not here yet

  • Streaming responses (this v1 is a single non-streaming completion, which keeps the insert atomic).