sharepoint-html
Author HTML that renders in SharePoint's OneUp HTML viewer and publish it into the user's own OneDrive / SharePoint. Use this skill whenever the user wants to create, host, publish, share, get a link for, or update a web page, dashboard, report, diagram, prototype, or slide deck inside Microsoft 365 — even if they don't say "SharePoint" or "OneDrive" by name. Covers the OneUp rendering contract (the CSP / sandbox rules that make HTML render instead of failing silently), embedding live SharePoint file data, and publishing via Microsoft Graph (primary) or the SharePoint Vroom API (when the agent is onboarded with SharePoint OAuth), plus ready-made templates.
日本語の概要は準備中です。原文の説明を表示しています。
含まれるファイル(15)
- SKILL.md16.0 KB
- .gitignore117 B
- assets/templates/dashboard.html5.2 KB
- assets/templates/livedata-dashboard.html5.7 KB
- assets/templates/livedata-list-dashboard.html13.7 KB
- assets/templates/README.md2.0 KB
- install.sh3.3 KB
- LICENSE1.1 KB
- README.md3.5 KB
- references/api.md11.0 KB
- references/contract.md3.1 KB
- references/live-data.md15.3 KB
- scripts/preflight.sh3.6 KB
- scripts/publish-graph.sh2.3 KB
- scripts/publish-to-folder.sh2.5 KB
SKILL.md(原文)
インストールする前に、エージェントに与えられる指示の中身を確認できます。
Publishing HTML to SharePoint (OneUp HTML viewer)
SharePoint already hosts HTML: save an .html file into OneDrive or SharePoint and
open it, and it renders in the OneUp HTML viewer — a sandboxed <iframe> under a
strict Content-Security-Policy. There is no separate hosting service to provision;
publishing is just writing an .html file to the user's drive as the signed-in
user, then opening the file's webUrl.
This skill teaches an agent two things:
- Author HTML that actually renders — the OneUp CSP + sandbox fail silently, so non-compliant HTML shows up blank or half-broken with no error. Follow the contract below and it just works.
- Publish it — upload the file with Microsoft Graph (primary) or the
SharePoint Vroom API (
_api/v2.0, for agents already holding a SharePoint token), then hand the user the returnedwebUrl.
The canonical, always-current copy of the authoring contract lives at your tenant's
discovery endpoint: https://<your-sharepoint-host>/_html (human page),
/_html/llms.txt (agent text), and /_html/help.json (structured). When in
doubt, fetch /_html/llms.txt — it is generated from the live viewer source.
⚠️ Before you publish: you are writing to the user's real drive
Publishing with this skill creates or overwrites a file in the user's own OneDrive / SharePoint, authenticated as that user. It is not a throwaway sandbox.
- Nothing becomes public automatically. The file is private to the user until they explicitly share it. But it is a real document in their drive.
- You MUST get the user's explicit confirmation before every upload and every overwrite. Show them the exact target (drive, folder, filename) and whether it creates a new file or replaces an existing one, and wait for a yes. See Confirm before writing.
- Overwrite is destructive.
PUT .../contentto an existing path replaces the file's contents. Confirm the path and that overwrite is intended.
The authoring contract (make HTML render in OneUp)
Your HTML runs inside <iframe sandbox="allow-scripts"> under a strict CSP that fails
silently. Follow these rules or the page renders blank/partial with no error.
Content-Security-Policy applied to your HTML:
default-src 'none';
script-src 'unsafe-inline' 'unsafe-eval';
style-src 'unsafe-inline';
img-src data: blob:;
font-src data: blob:;
connect-src 'none';
worker-src 'none';
object-src 'none';
base-uri 'none';
form-action 'none';
The wrapper iframe additionally applies frame-src 'none'.
Non-negotiable rules:
- No external resources. No
<script src>,<link href>,<img src=https://…>,@import,url(https://…), remote fonts, or CDNs. Inline everything or usedata:/blob:URIs. - All script must be inline
<script>blocks. No module imports, noimport(), no<script src>. - All styling must be inline
<style>orstyle="…". No<link rel="stylesheet">. - No network at runtime —
fetch,XMLHttpRequest,WebSocket,sendBeacon,EventSourceare all blocked (connect-src 'none'). To read SharePoint file data at view time, use the LiveData manifest (below) — it is the only sanctioned data path. - No storage primitives —
localStorage,sessionStorage,indexedDB,document.cookie(opaque-origin sandbox). For cross-reload state, setlocation.hashdirectly (e.g.location.hash = '#slide=3'). Do not usehistory.pushState/replaceState— the sandboxed document's base URL is inherited from the wrapper'sblob:origin, so anyurlargument (even a bare#hash) throwsSecurityError. - No top-level navigation, popups, form submission, workers, or plugins.
alert/confirm/promptare no-ops. - Inline
on*=handlers work (they're rewritten to nonced scripts) but are an XSS sink if they template untrusted data — preferaddEventListenerfor computed/user/fetched data. - Save as UTF-8 (the file-creation APIs below write UTF-8; add a BOM if authoring by hand and non-ASCII renders wrong).
Links: <a href> opens only for same-tenant SharePoint hosts or the external
allowlist; javascript: / vbscript: / data: hrefs are rejected.
Live SharePoint data (the only runtime data source)
Runtime fetch is blocked. To show live SharePoint file content, embed a LiveData
manifest — the host prefetches each item server-side with the viewer's credentials and
injects the results before your script runs:
<script type="application/json" class="ka-livedata-manifest">
[{ "spItemUrl": "https://contoso.sharepoint.com/_api/v2.0/drives/{driveId}/items/{itemId}", "fileName": "data.csv" }]
</script>
Before your script runs, the host sets window.__LD_RESULTS__, keyed by the exact spItemUrl.
Each value is { format, content, error?, metadata } — read content (a string) and check error.
Non-obvious but essential:
- Always include
fileName(with extension) in each item — the host picks thecsv/xlsx-sheets/textdecoder from it. Without it an.xlsxcomes back unreadable and a.csvis not parsed as csv. spItemUrlmust contain/drives/{driveId}/items/{itemId}(the origin is ignored, rebuilt from the viewer session). Get those ids by resolving the file:GET /shares/{u!token}/driveItem→parentReference.driveId+id.- Refresh RE-LOADS your iframe with fresh data —
postMessage({type:'ka-html-viewer-refresh'}, '*')(debounced 5s). There is no inbound "updated" event to listen for. - Treat the content as untrusted — build DOM with
textContent, neverinnerHTMLit. - Caps: 32 items/page (over-cap drops all results), 50 MB/item; formats: text, csv, xlsx-sheets, rows.
SharePoint lists — a manifest item can also point at a list (kind:"list" with webUrl + listId,
plus optional select of INTERNAL column names). The host renders it server-side and injects it as
format:"rows" — content is a JSON string { headers, rows } (already flattened; up to 100,000 rows,
truncation sets a non-blocking warning). Resolve listId + internal column names at authoring time via
GET {webUrl}/_api/web/lists/getbytitle('{Name}')/fields?$select=InternalName,Title,TypeAsString (or Graph
/sites/{site-id}/lists/{list-id}/columns). Internal names can differ from the display title (e.g. "City"
→ Ciity). See references/live-data.md.
Full protocol + a complete worked dashboard: references/live-data.md
(also mirrored in your tenant's /_html/llms.txt). Table-only starter:
assets/templates/livedata-dashboard.html.
Don't have HTML yet? Start from a template
If the user wants to publish something but has no HTML, use a ready-made, CSP-compliant
template from assets/templates/ instead of hand-writing:
| Template | Use it when the user wants to… |
|---|---|
dashboard.html | …build a self-contained metrics/status dashboard (no external data). |
livedata-dashboard.html | …render live SharePoint file data (csv/xlsx/text) via the LiveData manifest. |
livedata-list-dashboard.html | …render a live SharePoint list (kind:"list" → format:"rows") — KPIs, category charts, table. |
Read the chosen file, replace its <!-- REPLACE: … --> placeholders with the user's real
content, verify it against the contract above, then publish.
Step 1 — Author (or fill in) compliant HTML
Produce a single self-contained .html document that obeys the contract. Everything inline;
no external references; LiveData manifest if it needs SharePoint data.
Step 2 — Get an access token
Publishing is authenticated as the user. You need an OAuth 2.0 bearer token (Azure AD).
Primary — Microsoft Graph:
- Scope (delegated):
Files.ReadWrite(write to the user's own drive). UseFiles.ReadWrite.AllorSites.ReadWrite.Allto write to other libraries/sites the user can access. - Acquire it with the user's identity via MSAL (interactive, device-code, or an
existing signed-in session). Do not invent or hardcode tokens. If you don't already
have a Graph token, run an MSAL flow — see
references/api.md.
Alternative — SharePoint Vroom (use when the agent is already onboarded with a
SharePoint OAuth token, e.g. an add-in / SPFx / on-behalf-of flow): a token whose audience
is the SharePoint resource (https://{tenant}.sharepoint.com or -my.sharepoint.com),
scope AllSites.Write / MyFiles.Write. Same driveItem calls, different base URL.
Full token flows, scopes, and consent are in references/api.md.
Step 3 — Confirm, then publish
Confirm before writing
First preflight the HTML — run scripts/preflight.sh <file>; it greps for forbidden APIs and checks
LiveData manifest items (file items need spItemUrl + fileName; kind:"list" items need spItemUrl +
webUrl + listId) ("renders blank with no error" is the top failure). Then list the destination
folder (GET …/children) to detect a name collision, so you can tell the user accurately whether this
is a create or an overwrite.
Before the upload call, show the user exactly what will happen and get a yes:
About to publish to SharePoint/OneDrive:
Account: user@contoso.com
Location: OneDrive › Documents/Agent HTML/
File: sales-dashboard.html
Action: Create new file (or: Overwrite existing file — REPLACES its contents)
Renders at: <webUrl>?web=1 (?web=1 opens the OneUp viewer; the bare webUrl downloads)
Proceed?
Only continue on an explicit yes. For overwrite, make the destructive nature explicit.
Publish via Microsoft Graph (primary)
Simple upload (files ≤ 4 MB — plenty for inlined HTML). New file by path:
PUT https://graph.microsoft.com/v1.0/me/drive/root:/Agent HTML/<name>.html:/content
Authorization: Bearer <token>
Content-Type: text/html
<!DOCTYPE html> … your document …
Response 201 Created (new) / 200 OK (replace) → a driveItem. Read webUrl, then
give the user <webUrl>?web=1 — the ?web=1 opens it in the OneUp viewer; the bare webUrl
downloads the .html file:
{
"id": "01ABC…",
"name": "sales-dashboard.html",
"size": 84213,
"webUrl": "https://contoso-my.sharepoint.com/personal/user_contoso_com/Documents/Agent%20HTML/sales-dashboard.html",
"file": { "mimeType": "text/html" }
}
For files > 4 MB use an upload session (createUploadSession) — see
references/api.md.
Publish via SharePoint Vroom (alternative)
Same shape, SharePoint base URL, SharePoint-audience token. Use this when you already hold a
SharePoint OAuth token (SPFx / add-in / on-behalf-of) or want to target a specific SharePoint host
or site directly. (graph.microsoft.com already routes own-drive uploads to the caller's farm —
including dogfood rings like *.sharepoint-df.com — so Graph alone is usually enough.)
PUT https://{tenant}-my.sharepoint.com/_api/v2.0/me/drive/root:/Agent HTML/<name>.html:/content
Authorization: Bearer <sharepoint-token>
Content-Type: text/html
<!DOCTYPE html> … your document …
Returns the same driveItem (read webUrl). Full details, including site-drive paths
(/_api/v2.0/drives/{driveId}/items/{itemId}/content), in
references/api.md.
Publish into a SharePoint site library (instead of your OneDrive)
Same call against a site drive. With Graph (scope Sites.ReadWrite.All):
PUT https://graph.microsoft.com/v1.0/sites/{site-id}/drive/root:/Agent HTML/<name>.html:/content
or Vroom against the site host:
PUT {siteUrl}/_api/v2.0/drive/root:/Agent HTML/<name>.html:/content
The site drive root is its default document library ("Shared Documents"), so keep the path
root-relative. Resolve {site-id} with GET /sites/{host}:/sites/{path} (or /teams/{path}).
Publish by folder URL — fewest calls (Shares API)
If you only have the destination folder's URL, skip resolving drive/site ids — encode the URL as a sharing token and upload into it directly:
- Encode:
u!+ unpadded base64url of the folder URL (base64, strip=,/→_,+→-). GET /shares/{u!token}/driveItem→ the folder'sid+parentReference.driveId(one call).PUT /drives/{driveId}/items/{folderId}:/<name>.html:/content→ upload.
That's 2 calls, and it works for any OneDrive, site, or library. Details in
references/api.md; ready-made
script: scripts/publish-to-folder.sh.
Step 4 — Open it
Give the user <webUrl>?web=1 (the webUrl from the response with ?web=1 appended). The
?web=1 renders the HTML in the OneUp viewer; the bare webUrl downloads the .html file.
webUrl is stable across updates, so links keep working after you modify.
Updating / modifying an asset you created
To change a published file, overwrite it — same path (or item id), same call:
PUT https://graph.microsoft.com/v1.0/me/drive/items/{item-id}/content
Authorization: Bearer <token>
Content-Type: text/html
<!DOCTYPE html> … updated document …
or by path: PUT /me/drive/root:/Agent HTML/<name>.html:/content.
Overwrite replaces the file's contents — confirm with the user first (show the target
- that it replaces the existing file). The
webUrlstays the same. Vroom is identical with its base URL. To rename/move instead of replace content, usePATCH …/items/{item-id}(seereferences/api.md).
Error codes
| Code | Meaning | Action |
|---|---|---|
401 | Unauthorized | Missing/expired token, or wrong audience (Graph vs SharePoint). Re-acquire with the right scope. |
403 | Forbidden | Token lacks write scope (Files.ReadWrite), or the user can't write that location. |
404 | Not found | Wrong drive/item/path, or the parent folder doesn't exist (create it first). |
413 | Payload too large | File > 4 MB on simple upload — use an upload session. |
423 | Locked | The item is checked out / locked. |
507 | Insufficient storage | The user's drive is full. |
Blank / half-rendered page after opening → an authoring-contract violation (usually an
external resource or a runtime fetch). Re-check the contract.
Reference
references/api.md— full Graph + Vroom endpoint reference: authentication & scopes, token acquisition, request/response schemas, upload sessions, metadata update, and the driveItem shape.references/contract.md— the OneUp authoring contract in full.assets/templates/— ready-made CSP-compliant templates.- Live docs (authoritative, tenant-specific):
https://<your-sharepoint-host>/_html,/_html/llms.txt,/_html/help.json.
レビュー
まだレビューはありません。使ってみた感想をお寄せください。
コメント
ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。
まだコメントはありません。最初のコメントを書いてみませんか。