WITAN

Witan Exec · Render · Calc · Lint · Alternatives · Pricing · Agent Skills · Install Witan

---

# Witan Exec — Code Mode for Spreadsheets

One tool to read, write, verify, and search any workbook.

    $ witan xlsx exec report.xlsx --code '
      const result = await xlsx.setCells(wb, [
        { address: "Summary!B5", formula: "=SUM(Revenue!B2:B13)" }
      ])
      const lint = await xlsx.lint(wb, { rangeAddresses: ["Summary!A1:C10"] })
      return { touched: result.touched, errors: result.errors, warnings: lint.total }
    '
    {"ok":true,"result":{"touched":{"Summary!B5":"$1,250,000","Summary!B6":"$187,500","Summary!B10":"$3,750,000"},"errors":[],"warnings":0},"writes_detected":true}

Witan Exec replaces the currently Python scripting approach with a
purpose-built JavaScript runtime that talks directly to a high-fidelity
.NET spreadsheet engine. Currently your agent; writes Python, runs,
reads the file back, writes more Python, and repeats, only ever
approximating the spreadsheet with Python objects. Instead, Witan Exec
enables your agent to write one script that reads, writes, recalculates,
lints, and renders — all in a single execution, with results returned
as structured JSON.

## Four engines in one tool

Witan Exec comes with all the tools you need in a single entry point.

### The Edit Engine

Purpose-built methods for browsing and modifying workbooks,
designed for agents rather than humans.

Reading & Discovery:

Discover table structure automatically, then read by semantic label instead of hardcoded cell addresses.

    readCell, readRange, readRow, readColumn
    readRangeTsv, readRowTsv, readColumnTsv    // token-efficient TSV output
    findCells, findRows                          // text/regex/number search
    detectTables, tableLookup                    // automatic table detection
    getUsedRange, listSheets, listDefinedNames

Writing & Structure:

    setCells                                     // values, formulas, formats
    insertRowAfter, deleteRows
    insertColumnAfter, deleteColumns
    addSheet, deleteSheet, renameSheet

Dependency Tracing:

Trace which inputs drive a bottom-line number, or find every formula that would break if you changed a cell.

    getCellPrecedents, getCellDependents
    traceToInputs, traceToOutputs

Formula Testing:

Test what a formula would return without writing it to the workbook.

    evaluateFormula, evaluateFormulas             // test without writing

Styling:

    getStyle, setStyle
    getSheetProperties, setSheetProperties

This is a custom JavaScript library backed by a .NET RPC server —
combining the best language for agent scripting with the best
runtime for xlsx/xml fidelity.

### The Rendering Engine

    await xlsx.previewStyles(wb, "Sheet1!A1:F20")

Generate PNG screenshots of any cell range, directly in code.

### The Formula Engine

    const result = await xlsx.setCells(wb, [
      { address: "Sheet1!B5", formula: "=SUM(B1:B4)" }
    ])
    print(result.errors)  // New formula errors, if any

Every write triggers automatic recalculation. Errors reported
immediately.

### The Linting Engine

    const diagnostics = await xlsx.lint(wb)
    print(diagnostics.filter(d => d.severity === "Warning"))

Run all 11 semantic rules against the workbook from within your
code.

## How it works

    $ witan xlsx exec report.xlsx --expr 'await xlsx.readCell(wb, "Summary!A1")'

Witan spins up a sandboxed JavaScript runtime with @witan/xlsx
pre-loaded. The workbook is available as the global `wb`. Your code
calls methods on the `xlsx` object with access to 30+ methods for
every spreadsheet operation. The result is returned as structured JSON.

## Example scenario

### Discover, look up, trace, test, write, and verify

    // 1. Discover the workbook's structure
    const tables = await xlsx.detectTables(wb)
    const summary = tables.find(t => t.tableName === "Summary")

    // 2. Look up a value by label, not by hardcoded cell address
    const revenue = await xlsx.tableLookup(wb, {
      table: summary.address,
      rowLabel: "Total Revenue",
      columnLabel: "Q4"
    })

    // 3. Check what depends on this cell before changing it
    const downstream = await xlsx.getCellDependents(wb, revenue.address, 3)
    print(`Updating ${revenue.address} will affect ${downstream.cells.length} cells`)

    // 4. Test a formula before writing it
    const preview = await xlsx.evaluateFormula(wb, "Summary",
      `=${revenue.address}*1.1`)

    // 5. Write the update
    const result = await xlsx.setCells(wb, [{
      address: revenue.address,
      formula: `=${revenue.address.replace("Q4","Q3")}*1.1`
    }])

    // 6. Verify — lint and screenshot
    const lint = await xlsx.lint(wb, { rangeAddresses: [summary.address] })
    await xlsx.previewStyles(wb, summary.address)

    return { updated: revenue.address, downstream: downstream.cells.length,
             warnings: lint.diagnostics }

One tool call. Discover structure, look up by label, check impact,
test a formula, write, lint, and screenshot — all in one execution.

## Access tracking

Every exec call returns an accesses array showing exactly which
cells were read and written:

    {
      "ok": true,
      "stdout": "...",
      "result": { ... },
      "writes_detected": true,
      "accesses": [
        { "operation": "read", "address": "Summary!B2:B10" },
        { "operation": "write", "address": "Summary!B5" },
        { "operation": "write", "address": "Summary!B6" }
      ]
    }

## CLI reference

    witan xlsx exec <file> [flags]

| Flag | Description | Default |
|------|-------------|---------|
| --code | Inline JavaScript source | — |
| --script | Path to a JavaScript file | — |
| --stdin | Read JavaScript from stdin | — |
| --expr | Expression shorthand (wrapped as return (<expr>);) | — |
| --input-json | JSON value passed as input to the script | {} |
| --timeout-ms | Execution timeout in milliseconds (max 90000) | 30000 |
| --max-output-chars | Maximum stdout characters to capture (max 50000) | 20000 |
| --save | Persist writes and overwrite local workbook | false |
| --json | Output full response envelope | false |

Exactly one of --code, --script, --stdin, or --expr is required.

## Output format

Success:

    {"ok":true,"stdout":"...","result":<json>,"writes_detected":<bool>,"accesses":[...]}

Failure:

    {"ok":false,"stdout":"...","error":{"type":"...","code":"...","message":"..."}}

## Usage examples

    # Quick cell lookup
    witan xlsx exec report.xlsx --expr 'await xlsx.readCell(wb, "Summary!A1")'

    # Run a script file with parameters
    witan xlsx exec report.xlsx --script ./analyze.js --input-json '{"threshold":10}'

    # Edit and save
    witan xlsx exec report.xlsx --save --code '
      await xlsx.setCells(wb, [{ address: "Sheet1!A1", value: "Updated" }])
      return { ok: true }
    '

    # Pipe from stdin
    cat analysis.js | witan xlsx exec report.xlsx --stdin

---

© Witan Labs Inc. 2026
hello@witanlabs.com · API Docs · GitHub · Research · Terms · Privacy
Witan Exec AlternativesPricing
Agent Skills Install Witan
Witan Exec illustration

One tool to read, write, verify,
and search any workbook.

Example: write a formula, recalculate, and lint — in one call

$ witan xlsx exec report.xlsx --code '
  const result = await xlsx.setCells(wb, [
    { address: "Summary!B5", formula: "=SUM(Revenue!B2:B13)" }
  ])
  const lint = await xlsx.lint(wb, { rangeAddresses: ["Summary!A1:C10"] })
  return { touched: result.touched, errors: result.errors, warnings: lint.total }
'
{"ok":true,"result":{"touched":{"Summary!B5":"$1,250,000","Summary!B6":"$187,500","Summary!B10":"$3,750,000"},"errors":[],"warnings":0},"writes_detected":true}

Witan Exec replaces the currently Python scripting approach with a purpose-built JavaScript runtime that talks directly to a high-fidelity .NET spreadsheet engine. Currently your agent; writes Python, runs, reads the file back, writes more Python, and repeats, only ever approximating the spreadsheet with Python objects. Instead, Witan Exec enables your agent to write one script that reads, writes, recalculates, lints, and renders — all in a single execution, with results returned as structured JSON.

Four engines in one tool

Witan Exec comes with all the tools you need in a single entry point.

Generate PNG screenshots of any cell range, directly in code.

await xlsx.previewStyles(wb, "Sheet1!A1:F20")

Every write triggers automatic recalculation. Errors reported immediately.

const result = await xlsx.setCells(wb, [
  { address: "Sheet1!B5", formula: "=SUM(B1:B4)" }
])
print(result.errors)  // New formula errors, if any

Run all 11 semantic rules against the workbook from within your code.

const diagnostics = await xlsx.lint(wb)
print(diagnostics.filter(d => d.severity === "Warning"))

Purpose-built methods for browsing and modifying workbooks, designed for agents rather than humans.

Reading & Discovery

Discover table structure automatically, then read by semantic label instead of hardcoded cell addresses.

readCell, readRange, readRow, readColumn
readRangeTsv, readRowTsv, readColumnTsv    // token-efficient TSV output
findCells, findRows                          // text/regex/number search
detectTables, tableLookup                    // automatic table detection
getUsedRange, listSheets, listDefinedNames

Writing & Structure

setCells                                     // values, formulas, formats
insertRowAfter, deleteRows
insertColumnAfter, deleteColumns
addSheet, deleteSheet, renameSheet

Dependency Tracing

Trace which inputs drive a bottom-line number, or find every formula that would break if you changed a cell.

getCellPrecedents, getCellDependents
traceToInputs, traceToOutputs

Formula Testing

Test what a formula would return without writing it to the workbook.

evaluateFormula, evaluateFormulas             // test without writing

Styling

getStyle, setStyle
getSheetProperties, setSheetProperties

This is a custom JavaScript library backed by a .NET RPC server — combining the best language for agent scripting with the best runtime for xlsx/xml fidelity.

How it works

$ witan xlsx exec report.xlsx --expr 'await xlsx.readCell(wb, "Summary!A1")'

Witan spins up a sandboxed JavaScript runtime with @witan/xlsx pre-loaded. The workbook is available as the global wb. Your code calls methods on the xlsx object with access to 30+ methods for every spreadsheet operation. The result is returned as structured JSON.

Example scenario

Discover, look up, trace, test, write, and verify

// 1. Discover the workbook's structure
const tables = await xlsx.detectTables(wb)
const summary = tables.find(t => t.tableName === "Summary")

// 2. Look up a value by label, not by hardcoded cell address
const revenue = await xlsx.tableLookup(wb, {
  table: summary.address,
  rowLabel: "Total Revenue",
  columnLabel: "Q4"
})

// 3. Check what depends on this cell before changing it
const downstream = await xlsx.getCellDependents(wb, revenue.address, 3)
print(`Updating ${revenue.address} will affect ${downstream.cells.length} cells`)

// 4. Test a formula before writing it
const preview = await xlsx.evaluateFormula(wb, "Summary",
  `=${revenue.address}*1.1`)

// 5. Write the update
const result = await xlsx.setCells(wb, [{
  address: revenue.address,
  formula: `=${revenue.address.replace("Q4","Q3")}*1.1`
}])

// 6. Verify — lint and screenshot
const lint = await xlsx.lint(wb, { rangeAddresses: [summary.address] })
await xlsx.previewStyles(wb, summary.address)

return { updated: revenue.address, downstream: downstream.cells.length,
         warnings: lint.diagnostics }

One tool call. Discover structure, look up by label, check impact, test a formula, write, lint, and screenshot — all in one execution.

Access tracking

Every exec call returns an accesses array showing exactly which cells were read and written:

{
  "ok": true,
  "stdout": "...",
  "result": { ... },
  "writes_detected": true,
  "accesses": [
    { "operation": "read", "address": "Summary!B2:B10" },
    { "operation": "write", "address": "Summary!B5" },
    { "operation": "write", "address": "Summary!B6" }
  ]
}

CLI reference

witan xlsx exec <file> [flags]
Flag Description Default
--code Inline JavaScript source
--script Path to a JavaScript file
--stdin Read JavaScript from stdin
--expr Expression shorthand (wrapped as return (<expr>);)
--input-json JSON value passed as input to the script {}
--timeout-ms Execution timeout in milliseconds (max 90000) 30000
--max-output-chars Maximum stdout characters to capture (max 50000) 20000
--save Persist writes and overwrite local workbook false
--json Output full response envelope false

Exactly one of --code, --script, --stdin, or --expr is required.

Output format

Success:

{"ok":true,"stdout":"...","result":<json>,"writes_detected":<bool>,"accesses":[...]}

Failure:

{"ok":false,"stdout":"...","error":{"type":"...","code":"...","message":"..."}}

Usage examples

# Quick cell lookup
witan xlsx exec report.xlsx --expr 'await xlsx.readCell(wb, "Summary!A1")'

# Run a script file with parameters
witan xlsx exec report.xlsx --script ./analyze.js --input-json '{"threshold":10}'

# Edit and save
witan xlsx exec report.xlsx --save --code '
  await xlsx.setCells(wb, [{ address: "Sheet1!A1", value: "Updated" }])
  return { ok: true }
'

# Pipe from stdin
cat analysis.js | witan xlsx exec report.xlsx --stdin