Skip to main content

witan-cli

The Office toolkit for coding agents — edit, render, calculate, and lint Excel workbooks, plus render, script, and lint PPTX files.

Documentation | How we built it

Install

Quick Install Script

curl -fsSL https://witanlabs.com/install.sh | sh

Or try without installing: npx witan / uvx witan

From GitHub Releases

Download the latest artifacts from:

Example (macOS Apple Silicon):

curl -fsSL https://github.com/witanlabs/witan-cli/releases/latest/download/witan-darwin-arm64.tar.gz | tar -xz
install -m 0755 witan /usr/local/bin/witan

From PyPI

Install the bundled CLI and Python SDK from PyPI:

# one-shot run without permanent install
uvx witan --help

# persistent install
pip install witan

Python SDK example:

from witan import Workbook

with Workbook("report.xlsx") as wb:
    sheets = wb.list_sheets()
    tsv = wb.read_range_tsv("Summary!A1:F20")

Create and save a new workbook:

from witan import Workbook

with Workbook("model.xlsx", create=True) as wb:
    wb.add_sheet("Inputs")
    wb.set_cells([{"address": "Inputs!A1", "value": "Revenue"}])
    wb.save()

Async sessions are available for asyncio applications:

from witan import AsyncWorkbook

async with AsyncWorkbook("report.xlsx") as wb:
    cell = await wb.read_cell("Summary!A1")

Notebook and REPL sessions can use an explicit close instead of a context manager:

from witan import Workbook

wb = Workbook("report.xlsx")
tsv = wb.read_range_tsv("Summary!A1:F20")
wb.close()

In Jupyter/IPython, async sessions can use top-level await:

from witan import AsyncWorkbook

wb = AsyncWorkbook("report.xlsx")
cell = await wb.read_cell("Summary!A1")
await wb.close()

From npm

Install the bundled CLI and Node.js SDK from npm (requires Node.js 22+):

npm install witan

Node.js SDK example:

import { Workbook } from 'witan';

await using wb = await Workbook.open('report.xlsx');
const sheets = await wb.listSheets();
const tsv = await wb.readRangeTsv('Summary!A1:F20');

Create and save a new workbook:

import { Workbook } from 'witan';

await using wb = await Workbook.open('model.xlsx', { create: true });
await wb.addSheet('Inputs');
await wb.setCells([{ address: 'Inputs!A1', value: 'Revenue' }]);
await wb.save();

Alternative: explicit close

import { Workbook } from 'witan';

const wb = await Workbook.open('report.xlsx');
const tsv = await wb.readRangeTsv('Summary!A1:F20');
await wb.close();

From Source

Requires Go (version from go.mod):

go install github.com/witanlabs/witan-cli@latest

Quick Start

Run any command with npx witan or uvx witan without installing.

# Authenticate (recommended)
witan auth login

# Render a PPTX slide
witan pptx render deck.pptx --slide 1 -o slide-1.png

# Check a PPTX for chart-integrity, layout, and hidden-text issues
witan pptx lint deck.pptx

# Run Office.js-compatible JavaScript against a PPTX file
witan pptx exec deck.pptx --expr 'PowerPoint.run(async context => { const count = context.presentation.slides.getCount(); await context.sync(); return count.value })'

# Create a workbook from scratch
witan xlsx exec quickstart.xlsx --create --save --stdin <<'WITAN'
await xlsx.addSheet(wb, "Summary")
await xlsx.setCells(wb, [
  { address: "Summary!A1", value: "Metric" },
  { address: "Summary!B1", value: "Q1" },
  { address: "Summary!C1", value: "Q2" },
  { address: "Summary!A2", value: "Revenue" },
  { address: "Summary!B2", value: 1200, format: "$#,##0" },
  { address: "Summary!C2", value: 1500, format: "$#,##0" },
  { address: "Summary!A3", value: "Costs" },
  { address: "Summary!B3", value: 700, format: "$#,##0" },
  { address: "Summary!C3", value: 850, format: "$#,##0" },
  { address: "Summary!A4", value: "Profit" },
  { address: "Summary!B4", formula: "=B2-B3", format: "$#,##0" },
  { address: "Summary!C4", formula: "=C2-C3", format: "$#,##0" }
])
return await xlsx.readRange(wb, "Summary!A1:C4")
WITAN

# Render a range
witan xlsx render quickstart.xlsx -r "Summary!A1:C4"

# Recalculate formulas
witan xlsx calc quickstart.xlsx

# Lint formulas
witan xlsx lint quickstart.xlsx

# Run JS against workbook
witan xlsx exec quickstart.xlsx --expr 'await xlsx.readCell(wb, "Summary!C4")'

# Author a ListObject table in one call
witan xlsx exec model.xlsx --save --stdin <<'WITAN'
await xlsx.addListObject(wb, "Sheet1", {
  name: "SalesTable",
  ref: "A1:C4",
  showTotalsRow: true,
  columns: [
    { name: "Region", totalsRowLabel: "Total" },
    { name: "Sales", totalsRowFunction: "sum" },
    { name: "DoubleSales", calculatedColumnFormula: "=B2*2" }
  ],
  rows: [
    [{ value: "North" }, { value: 10 }, {}],
    [{ value: "South" }, { value: 20 }, {}]
  ]
})
return await xlsx.readRange(wb, "SalesTable")
WITAN

# Author a What-If Data Table block
witan xlsx exec model.xlsx --save --stdin <<'WITAN'
await xlsx.addDataTable(wb, "Sheet1", {
  type: "oneVariableColumn",
  ref: "E1:F4",
  columnInputCell: "H1",
  inputValues: [5, 10, 15],
  formulas: ["=H1*2"]
})
return await xlsx.getDataTable(wb, "Sheet1!E1:F4")
WITAN

# Author a chart from workbook data
witan xlsx exec dashboard.xlsx --save --stdin <<'WITAN'
await xlsx.addChart(wb, "Summary", {
  name: "Revenue",
  position: { from: { cell: "F2" }, to: { cell: "N18" } },
  groups: [
    {
      type: "column",
      series: [
        {
          name: { ref: "Data!B1" },
          categories: "Data!A2:A9",
          values: "Data!B2:B9"
        }
      ]
    }
  ],
  title: { text: "Revenue" },
  legend: { position: "right" }
})
await xlsx.previewStyles(wb, "Summary!F2:N18")
WITAN

What This CLI Covers

witan-cli exposes four spreadsheet commands:

  • witan xlsx calc
  • witan xlsx exec
  • witan xlsx lint
  • witan xlsx render

The PyPI package also exposes witan.Workbook and witan.AsyncWorkbook, backed by witan xlsx rpc subprocess sessions. Public SDK methods use snake_case names matching the xlsx exec operation surface, such as read_range_tsv, find_cells, sweep_inputs, set_cells, add_chart, and set_conditional_formatting.

The lower-level Witan spreadsheet runtime supports broader workbook operations; this CLI focuses on the four agent-facing workflows above.

For presentations, the CLI provides witan pptx exec, witan pptx render, and witan pptx lint.

Auth, Config, and Modes

Authentication can be done via witan auth login, --api-key, or WITAN_API_KEY. Use witan auth status to inspect the active credential, validation state, and selected organization.

Environment variables:

  • WITAN_API_KEY: API key (optional when using witan auth login)
  • WITAN_API_URL: API base URL override (default: https://api.witanlabs.com)
  • WITAN_STATELESS: set 1 or true to force stateless mode
  • WITAN_CONFIG_DIR: override config directory (default: ~/.config/witan)
  • WITAN_MANAGEMENT_API_URL: management API override for auth login/token exchange

Modes:

  • Stateful (default when authenticated): uploads workbook revisions and reuses them across commands
  • Stateless (--stateless or WITAN_STATELESS=1): sends workbook bytes on every request, no server-side file reuse

In stateful mode, load-balancer affinity cookies are persisted at ~/.config/witan/cookies.json or $WITAN_CONFIG_DIR/cookies.json when WITAN_CONFIG_DIR is set.

witan xlsx exec --create always uses the stateless exec endpoint and only supports new .xlsx targets.

Limits:

  • Workbook inputs must be <= 25MB.

Development

# build local binary
make build

# run test suite
make test

# static checks
make vet
make format-check

# build release artifacts into dist/
make dist VERSION=v0.1.0

# build PyPI wheels (stable tags only)
make pypi-wheels VERSION=v0.1.0

The local binary is written to ./witan.

Release Process

Releases are handled by GitHub Actions:

  • Publish workflow: .github/workflows/witan-cli-release.yml (triggered by pushing v* tags)
  • Artifacts:
    • witan-darwin-arm64.tar.gz
    • witan-darwin-amd64.tar.gz
    • witan-linux-amd64.tar.gz
    • witan-linux-arm64.tar.gz
    • witan-windows-amd64.zip
    • witan-windows-arm64.zip
    • witan-install.sh
    • witan-*.whl (PyPI wheels for supported platforms; stable tags only)
    • witan-checksums.txt

PyPI publishing:

  • Stable tags (vX.Y.Z) publish wheels to PyPI using GitHub OIDC trusted publishing.
  • Pre-release tags (for example v1.2.3-rc.1) skip PyPI publish.

GitHub release publishing:

  • The workflow uploads artifacts directly to the matching GitHub Release tag.
  • If the release already exists (for example, created in the GitHub UI), assets are attached with --clobber.

Cutting a release (UI-driven):

  1. Add release notes under ## Unreleased in CHANGELOG.md.
  2. Create a GitHub Release in the UI with a new tag vX.Y.Z (or prerelease tag vX.Y.Z-suffix).
  3. Tag push triggers Witan CLI Release.
  4. The workflow builds artifacts, attaches them to the GitHub Release, and publishes to PyPI for stable tags.
  5. On successful release, CI runs scripts/roll-changelog.sh, pushes the changelog update to a chore/changelog-release-X.Y.Z branch, and opens a PR into the default branch.
  6. For stable tags, verify witan==X.Y.Z on PyPI, witan --version, python -m witan --version, and from witan import Workbook, AsyncWorkbook.

Manual git tag ... && git push ... is equivalent to UI tag creation and triggers the same workflow.

Skills under skills/ are published independently of CLI releases — merging to main makes them live for npx skills add witanlabs/witan-cli. Each skill carries its own version; see skills/README.md.

CI

Go and Python CI runs in .github/workflows/golang.yml on pushes to main and pull requests. The workflow runs go test, go vet, pytest, mypy, and python -m compileall python/witan, plus skill checks (SKILL.md size limit, per-skill version bump on change).

Release files for witan 0.14.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for witan 0.14.0
File
witan-0.14.0-py3-none-win_arm64.whl Python 3 none Windows ARM64 Details
witan-0.14.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
witan-0.14.0-py3-none-musllinux_1_2_x86_64.whl Python 3 none Linux musl 1.2+ x86-64 Details
witan-0.14.0-py3-none-musllinux_1_2_aarch64.whl Python 3 none Linux musl 1.2+ ARM64 Details
witan-0.14.0-py3-none-manylinux_2_17_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details
witan-0.14.0-py3-none-manylinux_2_17_aarch64.whl Python 3 none Linux glibc 2.17+ ARM64 Details
witan-0.14.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
witan-0.14.0-py3-none-macosx_10_15_x86_64.whl Python 3 none macOS 10.15+ x86-64 Details

Total release size:29.1 MB

Release files / witan-0.14.0-py3-none-win_arm64.whl

Download URL witan-0.14.0-py3-none-win_arm64.whl
Size 3.5 MB
Tags Python 3 Windows ARM64
SHA-256 checksum
How to use checksums
ed3b964313ef7e77ed640145229ede00ec6c183a340f349de0241083bf9976c5
BLAKE2b-256 checksum
How to use checksums
0ff56b4a64abd20890121feb1f8b920e0bcb1ef4600af5001b9631cadd253338
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release files / witan-0.14.0-py3-none-win_amd64.whl

Download URL witan-0.14.0-py3-none-win_amd64.whl
Size 3.9 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
7bb4bbef83a0c894a377857b2c9fbc1e59a6fa5a971f38932b4da22cc0dbbe17
BLAKE2b-256 checksum
How to use checksums
d6e699a794e9a85fb7161fc2df887892c2bcf998dd2a4baf3b0166254e27f2ac
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release files / witan-0.14.0-py3-none-musllinux_1_2_x86_64.whl

Download URL witan-0.14.0-py3-none-musllinux_1_2_x86_64.whl
Size 3.8 MB
Tags Linux musl 1.2+ x86-64 Python 3
SHA-256 checksum
How to use checksums
005417aa17860420dcdee14a5030eee3fed44d6d1c487c93dcab0054d6d3b39e
BLAKE2b-256 checksum
How to use checksums
c55a3ba446c3b323d6c64c89df939984f431f35581bbd0ef127a2d80e8713187
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release files / witan-0.14.0-py3-none-musllinux_1_2_aarch64.whl

Download URL witan-0.14.0-py3-none-musllinux_1_2_aarch64.whl
Size 3.4 MB
Tags Linux musl 1.2+ ARM64 Python 3
SHA-256 checksum
How to use checksums
e6c99327ea11a52d93c45a06539121a42ee86985a4aef13ec5cf065a47fd8047
BLAKE2b-256 checksum
How to use checksums
49d876b8737fc5cd5f9a10cb135e0f0accc946a37e993a450086b9e2d6e90f7f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release files / witan-0.14.0-py3-none-manylinux_2_17_x86_64.whl

Download URL witan-0.14.0-py3-none-manylinux_2_17_x86_64.whl
Size 3.8 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
93d4cfb9fd93901a7d867d4a3dc03cb605b28aed8fe1bbfb0fb0cec2f791f1b9
BLAKE2b-256 checksum
How to use checksums
0416ff31ba6a6972b4de771ddf8f1d20993686a7202dc371f643d69d66766ac1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release files / witan-0.14.0-py3-none-manylinux_2_17_aarch64.whl

Download URL witan-0.14.0-py3-none-manylinux_2_17_aarch64.whl
Size 3.4 MB
Tags Linux glibc 2.17+ ARM64 Python 3
SHA-256 checksum
How to use checksums
9c2067bff2083e4f10ea90e5afa1f8d892b0e5ca26763e345f168ca63ca59d31
BLAKE2b-256 checksum
How to use checksums
68a03d90026e357bd457a74814de585301c740c915878188a79d6972f21ffa37
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release files / witan-0.14.0-py3-none-macosx_11_0_arm64.whl

Download URL witan-0.14.0-py3-none-macosx_11_0_arm64.whl
Size 3.5 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
1026fd038b91855338eaa6c4805aeb6df0d1461b594a05ed7f97b85f9b2025db
BLAKE2b-256 checksum
How to use checksums
7a0c1261f12d086f4bb73e6bb68e86ff470fb76fcd0b30339bd3fbccb5ae22f6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release files / witan-0.14.0-py3-none-macosx_10_15_x86_64.whl

Download URL witan-0.14.0-py3-none-macosx_10_15_x86_64.whl
Size 3.8 MB
Tags Python 3 macOS 10.15+ x86-64
SHA-256 checksum
How to use checksums
5f282e11899d81050226db403b789ce4909a63acd7633f18278dbe2079291eb7
BLAKE2b-256 checksum
How to use checksums
6e0aa8b92c713b856af354c7a16d7fb89a828cfddb902c01c03046e24a7940b6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.14.0 This release

8 release files

0.13.0

8 release files

0.10.4

8 release files

0.10.3

8 release files

0.10.0

8 release files

0.9.0

8 release files

0.8.0

8 release files

0.7.1

8 release files

0.7.0

8 release files

0.6.2

8 release files

0.6.1

8 release files

0.6.0

8 release files

0.5.0

8 release files

0.4.0

8 release files

0.3.1

8 release files

0.3.0

8 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page