Excel Tracker (Base Capability)
Depends on: none
What this is
Defines how the agent creates, reads, edits, and safeguards an Excel (.xlsx) file used as a structured, row-per-item tracker — as opposed to tracking the same information in a markdown table. This is a base capability: it says nothing about what the tracker is for. Domain-specific features (e.g., legal discovery tracking) depend on this spec for their mechanics and add their own schema on top.
Use an Excel tracker instead of a markdown table when the data is naturally row-per-item, needs to be filtered/sorted/checked off interactively by the user, and benefits from dropdowns, formulas, or a status field that gets updated repeatedly over the tracker's life. Markdown stays the right choice for prose, reasoning, and strategy content that doesn't decompose into atomic rows.
Assess first
- Confirm whether the data genuinely fits a row-per-item model (see above) before defaulting to Excel just because the source data happens to include a table.
- If installing this alongside a domain-dependent feature (e.g., legal discovery tracking) in the same session, install this feature's section first — the domain feature nests under it, not beside it (see Write below).
Ask, only if needed
Nothing to ask before installing this base capability itself — it has no user-facing configuration of its own. A dependent domain feature may have its own Ask step.
Write
Access method — PowerShell + Excel COM automation
This is the only tested and approved method for creating or editing an Excel tracker in this environment.
- The agent uses
windows-mcp-*:PowerShellto drive Excel via COM automation (New-Object -ComObject Excel.Application), notopenpyxl/Python, and not the genericwindows-mcp-*:FileSystemcopy/write modes for the file's binary content. - Excel COM automation is confirmed available in this environment. It produces a genuine, fully-featured .xlsx — real formulas (not hardcoded values), data-validation dropdowns, multiple sheets, cross-sheet references — authored natively on the user's machine, with no file-transfer step. In practice, this combination (PowerShell driving Excel via COM, in-session, on the same machine) is genuinely fast for both the edit itself and the pre-edit backup — this is the actual reason — not just convention — that COM-native is the default and sandbox-then- transfer is rejected below: transferring a file (or splitting one across base64-encoded chunks) gives up real, observed speed for no benefit.
- Do not build the .xlsx in a separate sandbox/container environment and transfer the finished binary onto the user's filesystem — this was tried and rejected; base64-encoding a binary across that boundary is slow and produces enormous, unreadable tool-call payloads for no benefit over building the file natively where it will live.
Mandatory cleanup: every script that opens Excel via COM must close the workbook and quit the Excel application object, including on error paths (wrap in try/finally for anything complex enough to risk a mid-script failure). An unclosed COM reference leaves an invisible EXCEL.EXE process running on the user's machine.
When a direct single-pass COM write genuinely can't produce the needed structure (data needs real assembly or transformation before it maps cleanly into cells/sheets/formulas): this is still not a reason to fall back to the sandbox-then-transfer pattern rejected above. Assemble or compute the data first (still natively, still on the user's machine, same session), then write it down via COM as a distinct second step, once the structure is actually ready. Two native steps — prepare, then write — is fine; a transferred binary is not, regardless of how the data got assembled. Base64-encoding a file across any tool or environment boundary remains rejected outright, for transfer or for splitting a large file into parts alike — if a write genuinely needs priming, prime it locally, then write it locally; never encode-and-move as a substitute for either step.
Known behavior to account for: Excel auto-reformats values written as date-like strings (e.g., a cell written as 2026-08-09 reads back as 8/9/2026). If a tracker schema includes a date field, decide explicitly whether it should be a true Excel date value (sortable, formula-compatible) or a fixed text string, and format/write accordingly.
Backup convention — pre-edit copy, not a periodic archive
Every edit to a tracked Excel file is preceded by a timestamped backup copy. This is distinct from and in addition to any repository-level backup the user runs separately — a once-daily backup does not protect against a bad edit made minutes earlier.
Folder convention: the backup folder sits beside the tracked file, named _backup (underscore prefix, no other qualifier). Do not use the word archive — an archive implies deliberate, meaningful retention of historical versions; this is a rolling safety net whose only purpose is undoing a bad edit, not a version history to browse.
- Folder:
<same directory as the tracked file>\_backup\ - Filename pattern:
<original filename, without extension>_backup_<yyyyMMdd_HHmmss>.xlsx - Every backup file must be verified non-zero-byte immediately after creation, before the edit proceeds. If the backup fails or is zero bytes, STOP — do not make the edit.
Tool choice for the backup copy: use PowerShell's Copy-Item, invoked from inside the same PowerShell script that performs the edit — not a separate windows-mcp-*:FileSystem copy-mode tool call. Timed comparison: in-process Copy-Item costs roughly 3ms (warm cache); a separate windows-mcp-*:FileSystem tool call costs roughly 11.5 seconds for the same copy, because every standalone tool call pays a full orchestration round-trip. Always bundle backup + edit + save into a single PowerShell script, never as separate sequential tool calls, so the backup is effectively free rather than a step worth skipping under time pressure.
Verification discipline — applies every time
Every write session to a tracked Excel file follows this sequence:
- Confirm the target file exists and is non-zero before opening.
- Take the pre-edit backup (above); confirm it is non-zero.
- Open via COM, make the edit(s), save, close, quit, release the COM object.
- Confirm the file's modified timestamp changed and its size is sane.
- Re-open in a fresh, separate COM session (not the same object) and read back the edited cell(s) to confirm the write actually persisted to disk — this is the test that actually proves the round-trip works, not just that Save() didn't error.
Project cache sidecar — how a tracker gets referenced as context without caching the binary file
The .xlsx file itself is never placed in a Project Cache staging directory. Whatever project-level mechanism keeps key context loaded into every session is markdown/text-oriented — dropping a binary .xlsx into it breaks that pattern. Instead, the tracker gets a markdown sidecar, following the same convention already used for other non-text-native source documents (a .pdf gets a .pdf.md sidecar; an .xlsx tracker gets an .xlsx.md sidecar).
What the sidecar is: a flat markdown table mirroring the tracker's rows and columns exactly — not a narrative summary. It exists to be read as reference context, not read top-to-bottom by a person. The sidecar is pure output — never edited directly, and edits to it are never read back into the tracker. The .xlsx is always the source of truth.
Where it lives: beside the tracker, same folder, same base filename plus .md — e.g., <Tracker>.xlsx produces <Tracker>.xlsx.md in the same directory.
Generation trigger: on demand, not on every edit — specifically when the host project's context/cache-refresh routine runs, and only if the tracker's on-disk modified timestamp is newer than the sidecar's.
Extraction method for the sidecar: see FTR-12 (Markdown Sidecars) for the approved fast-extraction method for .xlsx files, since that guidance applies to any spreadsheet a project needs sidecar'd, not just Excel trackers specifically.
Installation & merge behavior — how this combines with dependent domain features
When this base feature and a domain-dependent feature that relies on it (e.g., legal discovery tracking) are both installed into a project's Agent Instructions, they are not written up as two separate, parallel sections. A dependent feature is documented as an extension nested under this feature's own section — not as a standalone section sitting beside it as if the two were independent capabilities.
Concretely: the Agent Instructions gain one EXCEL TRACKER section (access method, backup convention, verification discipline — everything above). A domain feature that depends on it does not get its own top-level section duplicating or restating any of that. Instead, it appears as a labeled sub-section or when working with [domain], additionally... addendum nested inside the same section — schema, nomenclature, and folder structure specific to that domain, with the backup/access/verification mechanics referenced by pointer, never copy-pasted.
This governs installation, not drafting — dependent specs remain separate files during development and review; the merge happens at the point a feature is actually installed into a project's live Agent Instructions.
What this doesn't cover
- Any specific column schema, dropdown values, or business meaning of a tracker's contents — that belongs in a domain-dependent feature (e.g., FTR-37, Legal Discovery Tracking).
- Multi-user or concurrent-edit handling — this assumes single-writer usage (the agent, on the user's behalf, one edit session at a time).
- Formula complexity beyond simple cross-sheet aggregation — for anything more complex, consult the project's general xlsx skill for LibreOffice-compatibility gotchas (untested in this Excel-COM-native context, since that skill targets a different toolchain).
Confirm
Confirm: Excel Tracker (Base Capability) is installed — an EXCEL TRACKER section now exists in admin\AGENT_INSTRUCTIONS.md covering access method, backup convention, and verification discipline. Any domain-dependent tracker feature installed later nests under this section rather than creating its own. Want to install another, or is that everything for now?