Thanks to visit codestin.com
Credit goes to github.com

Skip to content

witanlabs/witan-cli

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

163 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

witan-cli

The spreadsheet toolkit for coding agents — edit, render, calculate, and lint Excel workbooks.

Documentation | How we built it

Install

Quick Install Script

curl -fsSL https://witanlabs.com/agents/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 range
witan xlsx render report.xlsx -r "Sheet1!A1:F20"

# Recalculate formulas
witan xlsx calc report.xlsx

# Lint formulas
witan xlsx lint report.xlsx

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

# Create a new workbook from scratch
witan xlsx exec model.xlsx --create --save --code 'await xlsx.addSheet(wb, "Inputs"); return true'

# 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.

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.

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.

About

The spreadsheet toolkit for coding agents - edit, render, calculate, and lint Excel workbooks.

Topics

Resources

License

Stars

Watchers

Forks

Contributors