Integrating wb with LLM Agents
The safest way to put spreadsheets in an agent loop is to treat wb as the spreadsheet tool boundary. Let the model decide what to inspect or change, and let wb handle workbook parsing, patch validation, recalculation, and dependency tracing.
This is usually more reliable than asking a model to reason over raw OOXML, screenshots, or copied formula text.
Why wb Works Well for Agents
wb --mode agentforces JSON envelopes and structured help on stdout.wb capabilities --format jsonlets the agent discover commands, flags, and formats without scraping prose docs.wb read,wb edit,wb calc,wb dep, andwb infocover the common inspect/change/verify loop.wb edit --validate-only --plangives you a dry-run plan before anything is written back to disk.wb read --headers,--where, and--rangehelp you keep the prompt small and focused.
Recommended Agent Workflow
Start by discovering the tool shape once:
wb capabilities --format json
wb --mode agent help read
Inspect workbook structure before reasoning about specific cells:
wb info budget.xlsx
wb read --sheet Budget --range A1:F20 --headers --format json budget.xlsx
Have the model propose a JSON patch, then validate it before saving:
wb edit --format json --validate-only --plan \
--patch '[{"cell":"F18","formula":"SUM(F2:F17)"}]' \
budget.xlsx
Apply the patch only after validation succeeds:
wb edit --format json \
--patch '[{"cell":"F18","formula":"SUM(F2:F17)"}]' \
budget.xlsx
Recalculate and inspect downstream impact:
wb calc --format json --range F18 budget.xlsx
wb dep --format json --cell F18 --direction dependents budget.xlsx
wb read returns stored or cached values. After formula edits, call wb calc when the agent needs fresh evaluated results.
Use --format markdown when you want to paste a small table directly into the model. Use --mode agent or --format json when another tool will consume the response.
Minimal Wrapper Example
This Python wrapper gives an agent runtime one structured entry point for wb:
import json
import subprocess
def wb(*args, stdin=None):
proc = subprocess.run(
["wb", "--mode", "agent", *args],
input=stdin,
text=True,
capture_output=True,
check=False,
)
if proc.returncode != 0:
raise RuntimeError(proc.stderr.strip() or proc.stdout.strip())
payload = json.loads(proc.stdout)
if not payload.get("ok"):
err = payload.get("error", {})
raise RuntimeError(err.get("message", "wb command failed"))
return payload["data"]
caps = wb("capabilities")
sheet = wb("read", "--sheet", "Budget", "--range", "A1:F12", "--headers", "budget.xlsx")
patch = json.dumps([
{"cell": "F13", "value": "Variance"},
{"cell": "G13", "formula": "F11-F12"},
])
plan = wb("edit", "--validate-only", "--plan", "--patch", patch, "budget.xlsx")
result = wb("edit", "--patch", patch, "budget.xlsx")
recalc = wb("calc", "--range", "G13", "budget.xlsx")
If your framework supports named tools, exposing read, edit, calc, and dep as separate tools is usually better than hiding everything behind one generic shell command.
Prompting Guidelines
- Ask the model for exact sheet and cell references in every finding.
- Limit reads to the smallest useful range before asking for analysis.
- Prefer JSON patches over free-form edit instructions.
- Run
wb edit --validate-only --planbefore any write. - Run
wb calcafter edits that change formulas or formula inputs. - Use
wb depwhen the user asks where a number came from or what will break downstream.
In-Process Go Services
If your agent already runs inside a Go service, you can skip the CLI and use the library directly:
wb, err := werkbook.Open("budget.xlsx")
if err != nil {
log.Fatal(err)
}
sheet := wb.Sheet("Budget")
if err := sheet.SetFormula("G13", "F11-F12"); err != nil {
log.Fatal(err)
}
wb.Recalculate()
var buf bytes.Buffer
if err := wb.WriteTo(&buf); err != nil {
log.Fatal(err)
}
Use the CLI when you want a language-agnostic tool boundary. Use the Go API when the agent backend already lives inside a Go process.