Office Macros skill for Codex

VBA and Office Scripts that finish in seconds. Codex decides between VBA and Office Scripts from where the workbook lives and how it must run, then writes macros that read and write whole ranges as arrays, never Select, and always restore calculation and events on error. It works from exported .bas and .ts source, reads existing macros with olevba, and leaves Outlook sends for you to confirm.

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- office-macros

Installs to ~/.agents/skills/office-macros/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $office-macros, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Writes and fixes Excel, Word and Outlook VBA macros and Excel Office Scripts (TypeScript) for Excel on the web and Power Automate - bulk array reads instead of cell loops, error handlers that restore application state, and macro-security-aware delivery. Use when the user asks for a VBA macro, a slow or broken .xlsm, an Office Script, a button that automates a workbook, or a Power Automate flow that runs a script.

Use it when

  • A workbook needs a macro or a button that automates a manual routine
  • An existing .xlsm macro is slow, fragile or throws errors
  • Excel on the web or Power Automate needs an Office Script
  • Macros stopped running after a file was emailed or downloaded

Use something else when

How to check the result

Run on a copy with production-sized data, compare row counts and a checksum column with a manual run, then force an error and confirm Excel's calculation and events are restored.

The mistake it prevents

Looping cell by cell with Select and ActiveSheet, which is slow and silently edits whichever workbook happens to be active.

~/.agents/skills/office-macros/SKILL.md

--- name: office-macros description: Writes and fixes Excel, Word and Outlook VBA macros and Excel Office Scripts (TypeScript) for Excel on the web and Power Automate - bulk array reads… license: MIT ---

Done well means: the macro runs in seconds on real data sizes, leaves Excel in the state it found it (screen updating, calculation, events) even after an error, and the user can read, rerun and trust it. Choose the platform first; most macro pain comes from picking the wrong one.

Choose VBA or Office Scripts

SituationChoose
Desktop Excel/Word/Outlook only, needs file system, other apps, UserFormsVBA
Workbook lives in OneDrive/SharePoint, used in Excel on the webOffice Scripts
Must run unattended on a schedule or from a form/email triggerOffice Scripts + Power Automate
Shared with Mac usersOffice Scripts (VBA on Mac lacks Windows APIs and ActiveX)
Pure data transformation that could live outside ExcelPython: $spreadsheet-automation
A formula could do itWrite the formula: $excel-formulas

Workflow

- [ ] 1. Get a copy of the workbook and a description of one manual run, step by step
- [ ] 2. Inspect structure: sheet names, tables (ListObjects), named ranges, data sizes
- [ ] 3. Write the macro against a copy, never the user's only file
- [ ] 4. Run on the copy; compare output with one manual run
- [ ] 5. Add the error handler, logging and a confirmation before destructive steps
- [ ] 6. Deliver as .bas/.ts source plus instructions, not only inside a binary file

Codex cannot open the VBA editor. Work with exported modules (.bas, .cls, .frm) as text. To read macros already inside an .xlsm or .docm, olevba workbook.xlsm from the oletools package prints them (pip install needs network). An .xlsm is a zip whose code sits in a binary vbaProject.bin; never edit that blob directly.

VBA patterns

Skeleton with state restore

Option Explicit

Public Sub BuildMonthlySummary()
    Dim calcMode As XlCalculation
    calcMode = Application.Calculation
    On Error GoTo Fail

    Application.ScreenUpdating = False
    Application.EnableEvents = False
    Application.Calculation = xlCalculationManual

    Dim ws As Worksheet
    Set ws = ThisWorkbook.Worksheets("Data")
    Dim lastRow As Long
    lastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    If lastRow < 2 Then Err.Raise vbObjectError + 1, , "No data rows on sheet Data"

    Dim src As Variant
    src = ws.Range("A2:D" & lastRow).Value2          ' one read: 2-D array, 1-based

    Dim totals As Object
    Set totals = CreateObject("Scripting.Dictionary")
    Dim r As Long
    For r = 1 To UBound(src, 1)
        totals(src(r, 2)) = totals(src(r, 2)) + src(r, 4)
    Next r

    Dim out() As Variant, k As Variant, i As Long
    ReDim out(1 To totals.Count, 1 To 2)
    For Each k In totals.Keys
        i = i + 1
        out(i, 1) = k: out(i, 2) = totals(k)
    Next k

    With ThisWorkbook.Worksheets("Summary")
        .Range("A2:B" & .Rows.Count).ClearContents
        .Range("A2").Resize(UBound(out, 1), 2).Value2 = out   ' one write
    End With

Cleanup:
    Application.Calculation = calcMode
    Application.EnableEvents = True
    Application.ScreenUpdating = True
    Exit Sub
Fail:
    MsgBox "BuildMonthlySummary failed: " & Err.Description, vbExclamation
    Resume Cleanup
End Sub

Rules that make VBA fast and predictable:

  • Option Explicit in every module; declare Long, not Integer (overflows at 32,767).
  • Never Select or Activate; reference ranges through a worksheet variable.
  • Read and write whole ranges as arrays. A cell-by-cell loop over 50k rows takes minutes; the array version takes well under a second.
  • Fully qualify: ThisWorkbook.Worksheets("Data"), not ActiveSheet or Sheets("Data") (the latter picks whichever workbook is active).
  • Prefer ListObjects (ws.ListObjects("tblSales").DataBodyRange) over hard-coded ranges.
  • Value2 skips Currency/Date coercion and is faster; format dates on output.
  • Find the last row with End(xlUp) on a column that is always filled, not UsedRange.

Word and Outlook

  • Word: edit through ActiveDocument.Content.Find with .Execute Replace:=wdReplaceAll and ranges; avoid moving the Selection.
  • Outlook: create mail with Application.CreateItem(olMailItem), call .Display so the user reviews it. Use .Send only after the user explicitly confirms bulk sending, and expect the Outlook object-model guard prompt on unmanaged machines.

Office Scripts (Excel on the web)

function main(workbook: ExcelScript.Workbook, minAmount: number = 0): string {
  const data = workbook.getWorksheet("Data");
  if (!data) throw new Error("Sheet 'Data' not found");
  const used = data.getUsedRange();
  if (!used) return "Sheet is empty";

  const rows = used.getValues();                 // one read
  const header = rows.shift() as string[];
  const amountCol = header.indexOf("Amount");
  if (amountCol < 0) throw new Error("No 'Amount' column");

  const kept = rows.filter(r => Number(r[amountCol]) >= minAmount);
  let out = workbook.getWorksheet("Filtered");
  if (out) out.delete();
  out = workbook.addWorksheet("Filtered");
  out.getRangeByIndexes(0, 0, kept.length + 1, header.length)
     .setValues([header, ...kept]);              // one write
  return `${kept.length} rows kept`;
}
  • main parameters after workbook become inputs in Power Automate; the return value becomes the action’s output.
  • Keep get*/set* calls out of loops: each one is a round trip to the workbook. Read once, transform plain arrays, write once.
  • Explicit any is not allowed; type values as (string | number | boolean)[][].
  • getWorksheet, getTable and getUsedRange return undefined when missing; check.
  • Scripts cannot reach the file system or other workbooks directly; Power Automate passes data in and out. External fetch works only when the script runs from Excel, not from Power Automate.
  • Power Automate runs have a synchronous timeout and a daily call cap per user; check Microsoft’s current “Office Scripts platform limits” page before designing a large job, and split work into batches of rows.

Delivery and macro security

  • Since 2022, Office blocks macros in files carrying the Mark of the Web (downloaded or emailed). The user unblocks via file Properties > Unblock, or IT adds a Trusted Location. Never advise lowering macro security to “Enable all macros”.
  • Ship the source: .bas exports in the repo, plus a README with import steps (Alt+F11 > File > Import File) and the button or shortcut to bind.
  • For reusable VBA across workbooks, suggest an .xlam add-in instead of copying modules.
  • Sign macros when the organisation requires it; self-signed certificates only satisfy the machine that created them.

Gotchas

  • On Error Resume Next left on hides every later failure. Scope it to one line and turn it off with On Error GoTo 0 or the handler label.
  • Deleting rows in a forward loop skips rows. Loop backwards, or build a union range or filter and delete once.
  • Regional settings: Range.Formula takes English function names and commas; FormulaLocal takes the user’s locale. Write Formula2 for dynamic arrays.
  • Workbook_Open and worksheet events fire during your macro unless EnableEvents is off.
  • Office Scripts recorded by the Action Recorder use hard-coded addresses; rewrite against tables or used ranges before reusing them.

Verification

  • Run against a copy with production-sized data and time it (Timer in VBA).
  • Compare output with a manual run on the same input: row counts and one checksum column.
  • Force an error (rename the source sheet) and confirm the handler restores calculation, events and screen updating.
  • For Office Scripts, run once from Excel, then once from the Power Automate test run, and read the returned string.

Handover

**Macro:** BuildMonthlySummary (Module modSummary.bas), Excel desktop, Windows and Mac
**Input:** sheet Data, columns A:D, header row 1
**Output:** sheet Summary A:B, cleared and rewritten each run
**Run:** button on Summary sheet, or Alt+F8 > BuildMonthlySummary
**Tested:** 48,210 rows in 0.6 s; totals match the manual pivot for September

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Office Macros"
  short_description: "VBA and Office Scripts that finish in seconds"
  default_prompt: "$office-macros This VBA macro takes ten minutes on 40k rows, make it fast"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
Just launched

Codex Skills Pro is live

79 premium skills for Codex, each with scripts, references and an evidence report that proves the result.

Bought one by one$882.21
All 79 skills$49
94% off

That's $0.62 a skill, paid once.

Get all 79 for $49Or pick single skills from $4.99 →

Secure checkout by Creem