TaskSultan Docs tasksultan.com

Capabilities

Excel

Read and write .xlsx workbooks through ctx.excel, backed by the ExcelJS engine, with no Microsoft Excel installation required.

The excel capability reads and writes .xlsx workbooks through ctx.excel. The engine is ExcelJS. It works on the file format directly, so no Microsoft Excel installation is required and the Robot runs headless on a server or in a container.

#The facade

ctx.excel is an ExcelFacade (framework/excel-types.ts). Automations never import ExcelJS themselves; the file format stays an engine concern.

  • resolvePath(file) resolves a relative workbook name against the facade's data directory.
  • readWorkbook(file) lists worksheets with their row and column counts.
  • readTable(file, { sheet }) reads a region as header-keyed objects, taking the first row as headers.
  • readRange(file, { sheet, range }) reads plain rows without assuming headers; range takes an A1:B3 form.
  • writeTable(file, headers, rows, options) creates or replaces a worksheet; overwrite defaults to true.
  • append(file, rows, { sheet }) adds rows after the last used row and creates the file or sheet when needed.
  • updateCells(file, { sheet, cells }) writes named cells, such as { A1: 'done', B2: 42 }.
  • createSheet, deleteSheet, toCSV, deleteFile and fileExists cover the remaining workbook tasks.

Every path is resolved against the data directory the Robot supplies, so an automation stays portable and never carries an absolute path.

#A worked example

This is the shape of process-invoices. One workbook is the transaction queue. A second workbook is the ledger the run writes to.

import type { RunContext, Transaction } from '../framework';

const OUTPUT_FILE = 'Results.xlsx';

async function record(ctx: RunContext, tx: Transaction): Promise<void> {
  await ctx.excel.append(
    OUTPUT_FILE,
    [{ InvoiceNumber: tx.id, Amount: Number(tx.payload.Amount ?? 0), Status: 'Processed' }],
    { sheet: 'Results' },
  );
  ctx.log.info(`Appended ${tx.id}`);
}

The automation declares capabilities: ['excel'] and reads its queue in init with ctx.excel.readTable(INPUT_FILE, { sheet: 'Invoices' }). Each row becomes one Transaction. A row that fails a business rule is recorded in the ledger in onBusinessException before the loop moves on.

#When the engine is missing

excel has one refusal code, EXCEL_UNAVAILABLE. The runner does not check the declaration before supplying the facade, so an automation that reaches ctx.excel outside the Robot runtime, with no provider, fails with that code on the first call rather than returning an empty table.

#Things that catch people out

readTable treats the first row as headers. A sheet with no header row should be read with readRange instead, which returns raw values.

writeTable overwrites by default. Pass { overwrite: false } if the sheet already holds rows you meant to keep.

deleteSheet refuses to remove the last remaining worksheet and createSheet errors when the sheet already exists. Both are deliberate and both say which file and which sheet in the message.

append derives headers from the first row when the file is new or the sheet is empty, then aligns each later row to the existing header columns. A row whose keys differ from the header simply gets empty cells for the columns it lacks.