CLI Scripting

witan pptx exec is the main presentations interface for agents. The CLI sends the deck and script to the configured Witan API, which runs the script inside a sandboxed, headless Office.js-compatible PowerPoint runtime.

Use it when a task needs to inspect, create, edit, export, or verify a deck from code.

Command

witan pptx exec <file.pptx> [flags]

Provide exactly one code source: --code, --script, --stdin, or --expr.

witan pptx exec deck.pptx --expr 'PowerPoint.run(async context => {
  const count = context.presentation.slides.getCount();
  await context.sync();
  return count.value;
})'

For multiline scripts, use --stdin:

witan pptx exec deck.pptx --stdin <<'JS'
return await PowerPoint.run(async context => {
  const slide = context.presentation.slides.getItemAt(0);
  slide.shapes.addTextBox("Updated", { left: 60, top: 60, width: 300, height: 80 });
  await context.sync();
  return slide.id;
});
JS

Flags

Flag Default Description
--code <ts/js> - Inline TypeScript or JavaScript source.
--script <path> - Path to a TypeScript or JavaScript file.
--stdin false Read TypeScript or JavaScript source from stdin.
--expr <expr> - Single-expression shorthand; wraps as return (<expr>);.
--input-json <json> {} JSON value exposed as the global input.
--input-file <key=@path> - Add a local PNG/JPEG file to input as a data:image/...;base64,... URI. Repeatable.
--locale <name> Environment-derived Execution locale. Falls back to WITAN_LOCALE, then LC_ALL, LC_MESSAGES, and LANG.
--stdin-timeout-ms <ms> 2000 Maximum time to wait for EOF when reading --stdin; 0 disables.
--timeout-ms <ms> 0 Execution timeout override. 0 uses the server default.
--max-output-chars <n> 0 Stdout capture limit override. 0 uses the server default.
--create false Create a new .pptx file instead of opening an existing file.
--save false Write returned presentation bytes to the target path.
--json false Use witan pptx --json exec ... to print the full response envelope.

Runtime Model

Scripts usually start with PowerPoint.run:

return await PowerPoint.run(async context => {
  const presentation = context.presentation;
  const slide = presentation.slides.getItemAt(0);
  const shapeCount = slide.shapes.getCount();
  await context.sync();
  return shapeCount.value;
});

OfficeExtension.ClientResult values, such as getCount(), should be read after await context.sync(). In Witan's headless runtime, load(...) and sync() are compatibility calls rather than network round trips: load(...) records requested properties, and sync() provides the Office.js sequencing point while resolving against the in-memory presentation model.

Creating Decks

Use --create with a path that does not exist:

witan pptx exec new-deck.pptx --create --save --stdin <<'JS'
return await PowerPoint.run(async context => {
  const slide = context.presentation.slides.getItemAt(0);
  slide.shapes.addTextBox("Created", { left: 60, top: 60, width: 300, height: 80 });
  await context.sync();
  return true;
});
JS

PowerPoint.createPresentation(...) is intentionally not implemented. File creation belongs to the CLI because the runtime runs headlessly inside the open presentation session.

Saving

Without --save, writes are in-memory for the request. Use --save when the modified .pptx should be written back to disk.

For uploaded presentations, updated bytes are returned only when writes are detected. For --create --save, the created file bytes are returned when execution succeeds.

Input Files

Use --input-file for image authoring:

witan pptx exec deck.pptx --save \
  --input-file logo=@./logo.png \
  --stdin <<'JS'
return await PowerPoint.run(async context => {
  const slide = context.presentation.slides.getItemAt(0);
  slide.shapes.addPicture(input.logo, {
    left: 54,
    top: 42,
    width: 120,
    height: 60
  });
  await context.sync();
  return true;
});
JS

Chart Extensions

Witan adds chart APIs to the Office.js PowerPoint object model:

const shape = slide.shapes.addChart(PowerPoint.ChartType.waterfall, [
  ["Step", "Amount"],
  ["Start", 120],
  ["Growth", 45],
  ["Churn", -18],
  ["End", 147]
], { left: 72, top: 100, width: 600, height: 340 });

const chart = shape.getChart();
chart.title.text = "Revenue Bridge";
chart.series.getItemAt(0).showConnectorLines = true;

Charts are real PowerPoint chart parts with embedded workbook data. See Charts and pptx API.

Sandbox

  • No filesystem access.
  • No network access.
  • No static or dynamic imports.
  • Top-level await is supported.
  • Use print(...) for progress output.
  • The script return value is serialized as JSON.

Verification

After visual edits, render the affected slide:

witan pptx render deck.pptx --slide 3 -o slide-3.png

For regression checks:

witan pptx render deck.pptx --slide 3 -o before.png
# ... edit ...
witan pptx render deck.pptx --slide 3 --diff before.png -o diff.png

See Render for rendering behavior and limits.