Pi for Excel is an AI agent that lives inside Excel's taskpane. It reads, writes, formats, and analyzes spreadsheets through natural conversation — backed by any major LLM provider. 24 built-in tools, a sandboxed extension runtime, and bridges to Python, tmux, and MCP servers make it a general-purpose automation surface for spreadsheets.
This page covers what Pi can do (Capabilities, Interface), then how it works under the hood (Model Layer, Lifecycle, Safety & Recovery, Testing).
Default Tools
24 tools in 5 categories — from cell reads to terminal sessions and MCP servers.
Excel.run() banned (context auto-provided). 20K code, 8K result. Requires user approval.Tool Wrapping Pipeline
Every tool passes through 3 wrapping layers before reaching the agent. Order matters — outermost wrapper executes first.
Full Pipeline
createAllTools() → applyExperimentalToolGates() → createToolsForIntegrations() → extensionManager.getRegisteredTools() → normalizeRuntimeTools() → withWorkbookCoordinator() → withConnectionPreflight() → applyToolOutputTruncation()
- Fingerprint comparison (FNV-1a hash of tool schemas) decides whether to call
agent.setTools() - Extension tool revision counter (monotonic) also triggers refresh when extensions add/remove tools
- Static tool ordering preserved for prompt cache stability
Extensions
Three extension surfaces — Connections, Plugins, and Skills — let users and the agent expand Pi's capabilities at runtime. Each has a dedicated tab in /extensions.
skills
Markdown documents (SKILL.md) that inject task-specific workflows into the conversation on demand. The agent calls skills → read when a task matches; the full document becomes part of the context.
import.meta.globskills/external/<name>/SKILL.md — managed installs via the skills tool or workspace discovery## Available Agent Skills; body injected on read. Session-scoped read cache avoids duplicates./extensions → Skills. Stored in SettingsStore (skills.activation.v1).
Credential requirements declared by plugins or built-in integrations. Each connection stores secrets,
surfaces auth state, and gates tool access — if a tool's connection isn't configured, the tool is
withheld from the model. Managed in /extensions → Connections.
{ownerId}.{connId}). Auto-rendered setup UI from plugin declarations.extensions_manager
Runtime code modules that register tools, commands, sidebar widgets, overlays, and connections. Users install them from /extensions; the agent can also create and install them from chat.
extensions_manager tool handles the full lifecycle: list → install → enable → reload → uninstall.
What Plugins Register
busyAllowed control. Appear in command menu.upsert / remove / clear. Placement, ordering, collapsible, size bounds./tools overlay.overlay.show(el). Single overlay per plugin at a time.18 Capability Gates
Trust Tiers & Runtime
/extensions.Lifecycle & Activation Bridge
{ownerId}.{connId}). Auto-rendered setup UI in /tools overlay.User Interface
PiSidebar (1,221 lines · LitElement · 350px) — purpose-built for Excel's narrow taskpane. Replaces pi-web-ui's ChatPanel + AgentInterface.
Keyboard Shortcuts
Agent Interface
What the model sees — Pi's awareness is layered. Some context is always present, some is injected fresh each turn, and some is fetched on demand via tools.
notes/index.md is the memory entry point for new sessions.Rules & Conventions
Two persistence layers that shape the agent's behavior. Rules are free-text guidance (what to do); conventions are structured formatting defaults (how to format). Both survive across sessions.
instructions
AGENTS.md — append or replace, ask on conflict.conventions
LLM Pipeline
From browser to model endpoint — authentication, proxy routing, and stream normalization.
5 Browser OAuth Providers
| Provider | Flow | Routing | |
|---|---|---|---|
| Anthropic | PKCE | Proxy for OAuth tokens (sk-ant-oat-*); API keys direct |
|
| OpenAI Codex | PKCE + JWT | Always proxy-routed; JWT decode for ChatGPT account ID | |
| Google Gemini CLI | Code Assist | Tiered provisioning (free/legacy/standard), LRO polling, VPC SC handling | |
| Google Antigravity | API key | 2 endpoints (prod + sandbox), default fallback project. JSON {token, projectId} |
|
| GitHub Copilot | Device code | Token refresh via GitHub API |
Stream Proxy (createOfficeStreamFn)
CORS Proxy (fetch interceptor)
anthropic-dangerous-direct-browser-access header when proxiedPrompt Caching
LLM prompt caching is prefix-based — providers cache the longest matching token prefix and reuse it on subsequent calls. Pi keeps the prompt structured so the prefix stays stable and the cache extends as far as possible each turn.
PrefixChangeReason recorded & counter incremented.buildOverview() cached per workbook, monotonic revision. Re-injected on structural changes.
onChanged events → dedup by cell → truncate at 50 → flush on send.
Stability invariants
selectToolBundle() returns full list in fixed order — no intent-based sub-setting. Extension revision tracking: hot-reloads skip setTools() when schema unchanged. src/context/tool-disclosure.ts
agent.setTools() when the metadata fingerprint actually differs. Schema-stable handler swaps are silent no-ops. src/taskpane/runtime-utils.ts
Compaction Strategy
Known prefix change triggers
["model"]["systemPrompt"]["systemPrompt"]["systemPrompt", "tools"]"tools"Baseline matrix documented in docs/cache-observability-baselines.md. PRs that change context shape must include a cache observability check.
Session Runtime
Each tab = one SessionRuntime with its own Agent, ActionQueue, QueueDisplay, and SessionPersistenceController. Multi-tab layout persisted per workbook.
idle → waiting_for_lock → holding_lock — prevents concurrent writes/compact race (agent.streamFn() outside Agent loop). Auto-compaction before each prompt.Boot Sequence
bootstrap.ts → initTaskpane() — 7 phases with timeouts and fallbacks for non-Excel environments (dev mode).
- Render loading UI
process.envshim, fetch interceptor (CORS proxy), model-selector patchOffice.onReady()3 s fallback for dev without Excel- Call
initTaskpane()60 s hard timeout
- SettingsStore init + proxy default seed
- Legacy migrations: web-search API keys → ConnectionStore, MCP tokens → ConnectionStore
- Remote proxy security warning
- Provider discovery (5 built-in + custom gateways)
- Credential restore:
pi auth.json(dev) or IndexedDB OAuth (prod) 6 s timeout - Auto-refresh expired tokens
- Show welcome login overlay if no providers
ChangeTracker.start()— cell change monitoringcreateOfficeStreamFn()— LLM call interceptorcreateWorkbookCoordinator()— FIFO write queue
PiSidebarmount + execution mode controllerConnectionManager+ExtensionRuntimeManager(reserved tool names from core + integrations)
- Bridge health probe (async — first turn waits for result)
- Runtime factory wiring
- Tab layout restore from SettingsStore (or create first runtime)
- Extension init 5 s timeout non-blocking
- Keyboard shortcuts, status bar, command menu
- Proxy polling 30 s interval
- Disclosure bar + proxy banner
6 defense boundaries — each enforced independently, no single-point-of-failure.
127.0.0.0/8, ::1), RFC1918, link-local. IPv4-mapped-IPv6 handling.javascript: / data: / file: links. No <img> from markdown (exfiltration risk → clickable link). Disable $...$ KaTeX (currency collision).innerHTML for user/tool/session content — DOM APIs or escapeHtml() / escapeAttr(). Queue display explicitly avoids innerHTML.••••. OAuth tokens in IndexedDB.Mutation Finalization
Every mutation tool calls finalizeMutationOperation():
WorkbookChangeAuditLog: persistent, 500-entry rotating, tagged with execution mode + workbook identityresult.details.recovery → dispatch created event or append unavailable note5 Snapshot Kinds
Restore creates an inverse snapshot before applying — enables "undo the undo". save-boundary-monitor polls Workbook.isDirty every 4s, clears checkpoints on user save.
Manual Full Backup
Office.getFileAsync("compressed") → 1MB chunks → base64 → workspace file. Stored under manual-backups/full-workbook/v1/.
| Suite | Files | Coverage | |
|---|---|---|---|
| test:models | Fast | Provider priority, family priority, parseMajorMinor |
|
| test:context | ~80 files | Tools, context injection, compaction, change tracker, session persistence, blueprint, recovery | |
| test:security | 9 files | SSRF proxy, CORS server, tmux/python bridges, extension source policy, marked safety, OAuth |
Build & Config
useDefineForClassFields: false for Litts-ignore, error on floating/misused promisesnpm run lint + npm run typecheckCredits
- Pi
- by Mario Zechner — the agent framework powering this project. Pi for Excel uses pi-agent-core, pi-ai, and pi-web-ui for the agent loop, LLM abstraction, and session storage.
- visual-explainer
- by Nico Bailon — the Pi extension used to generate this architecture page.
- whimsical.ts
- by Armin Ronacher — the rotating "Working…" messages are adapted from his Pi extension, rewritten for a spreadsheet audience.