Files
silo/docs/CALC_EXTENSION.md
Forbes afb382b68d feat: LibreOffice Calc extension, ODS library, AI description, audit design
Calc extension (pkg/calc/):
- Python UNO ProtocolHandler with 8 toolbar commands
- SiloClient HTTP client adapted from FreeCAD workbench
- Pull BOM/Project: populates sheets with 28-col format, hidden property
  columns, row hash tracking, auto project tagging
- Push: row classification, create/update items, conflict detection
- Completion wizard: 3-step category/description/fields with PN conflict
  resolution dialog
- OpenRouter AI integration: generate standardized descriptions from seller
  text, configurable model/instructions, review dialog
- Settings: JSON persistence, env var fallbacks, OpenRouter fields
- 31 unit tests (no UNO/network required)

Go ODS library (internal/ods/):
- Pure Go ODS read/write (ZIP of XML, no headless LibreOffice)
- Writer, reader, 10 round-trip tests

Server ODS endpoints (internal/api/ods.go):
- GET /api/items/export.ods, template.ods, POST import.ods
- GET /api/items/{pn}/bom/export.ods
- GET /api/projects/{code}/sheet.ods
- POST /api/sheets/diff

Documentation:
- docs/CALC_EXTENSION.md: extension progress report
- docs/COMPONENT_AUDIT.md: web audit tool design with weighted scoring,
  assembly computed fields, batch AI assistance plan
2026-02-01 10:06:20 -06:00

9.0 KiB

LibreOffice Calc Extension

Last Updated: 2026-02-01


Overview

The Silo Calc extension (silo-calc.oxt) is a LibreOffice Calc add-on that connects project BOM spreadsheets directly to the Silo parts database. Engineers work in their familiar spreadsheet environment while Silo handles part number generation, revision tracking, and data synchronization.

The extension is a Python UNO component packaged as an .oxt file. It uses only stdlib (urllib, json, ssl) -- no pip dependencies. The same SiloClient pattern and auth flow from the FreeCAD workbench is reused.


Architecture

Engineer's workstation                  Silo server (silod)
+--------------------------+           +------------------------+
| LibreOffice Calc         |           | Go API server          |
| +----------------------+ |   REST   | +--------------------+ |
| | Silo Extension (.oxt)| <--------> | | ODS endpoints      | |
| | - Pull/Push BOM      | |   API    | | (internal/ods)     | |
| | - Completion Wizard   | |          | +--------------------+ |
| | - AI Describe         | |          |         |              |
| +----------------------+ |           | +--------------------+ |
| UNO API | cells          |           | |  PostgreSQL        | |
| +----------------------+ |           | +--------------------+ |
| |  Project Workbook    | |           +------------------------+
| |  ~/projects/sheets/  | |
| |  3DX10/3DX10.ods     | |
+--------------------------+

Extension also calls OpenRouter AI API directly for
description generation (does not go through silod).

Extension Structure

pkg/calc/
  META-INF/manifest.xml          Extension manifest
  description.xml                Extension metadata (id, version, publisher)
  description/description_en.txt English description
  Addons.xcu                     Toolbar + menu registration
  ProtocolHandler.xcu            Dispatch protocol registration
  silo_calc_component.py         UNO DispatchProvider entry point
  pythonpath/silo_calc/
    __init__.py
    ai_client.py                 OpenRouter API client
    client.py                    SiloClient (HTTP, auth, SSL)
    completion_wizard.py         3-step new item wizard
    dialogs.py                   UNO dialog toolkit wrappers
    project_files.py             Local project file management
    pull.py                      Sheet population from server
    push.py                      Sheet changes back to server
    settings.py                  JSON settings (~/.config/silo/calc-settings.json)
    sheet_format.py              Column layout constants
    sync_engine.py               Row hashing, classification, diff
  tests/
    test_basics.py               31 unit tests (no UNO/network required)

Toolbar Commands

Button Command Description
Login SiloLogin Username/password dialog, creates API token
Pull BOM SiloPullBOM Assembly picker -> expanded BOM -> populates sheet
Pull Project SiloPullProject Project picker -> all project items -> multi-sheet workbook
Push SiloPush Classifies rows -> creates/updates items -> auto-tags project
Add Item SiloAddItem Completion wizard (category -> description -> fields)
Refresh SiloRefresh Re-pull (placeholder)
Settings SiloSettings API URL, token, SSL, OpenRouter config
AI Describe SiloAIDescription AI description from seller description

BOM Sheet Format

28 columns total: 11 visible core, 13 hidden properties, 4 hidden sync tracking.

Visible Columns

Col Header Notes
A Item Assembly/section header
B Level BOM depth (0=top)
C Source M=manufactured, P=purchased
D PN Part number (read-only for existing)
E Description Required for new items
F Seller Description Vendor catalog text
G Unit Cost Currency
H QTY Decimal quantity
I Ext Cost Formula =G*H (not stored)
J Sourcing Link URL
K Schema Schema name

Hidden Property Columns (L-X)

Manufacturer, Manufacturer PN, Supplier, Supplier PN, Lead Time, Min Order Qty, Lifecycle Status, RoHS, Country of Origin, Material, Finish, Notes, Long Description. Populated from revision properties, collapsed by default.

Hidden Sync Columns (Y-AB)

_silo_row_hash (SHA-256), _silo_row_status, _silo_updated_at, _silo_parent_pn. Used for change detection and conflict resolution.

Row Status Colors

Status Color Hex
synced light green #C6EFCE
modified light yellow #FFEB9C
new light blue #BDD7EE
error light red #FFC7CE
conflict orange #F4B084

Completion Wizard

Three-step guided workflow for adding new BOM rows:

  1. Category -- select from schema categories (F01-X08)
  2. Description -- required text, with AI generation offer when blank
  3. Common fields -- sourcing type, unit cost, quantity, sourcing link

If a manually entered PN already exists in the database, the PN Conflict Resolution dialog offers: use existing item, auto-generate new PN, or cancel.

New items are automatically tagged with the workbook's project code.


OpenRouter AI Integration

The extension calls the OpenRouter API (OpenAI-compatible) to generate standardized part descriptions from verbose seller descriptions. This is useful because seller descriptions are typically detailed catalog text while BOM descriptions need to be concise (max 60 chars, title case, component type first, standard abbreviations).

Configuration

Settings dialog fields (or OPENROUTER_API_KEY env var):

  • API Key -- OpenRouter bearer token (masked in UI)
  • AI Model -- default openai/gpt-4.1-nano
  • AI Instructions -- customizable system prompt

Workflow

  1. Paste seller description into column F
  2. Click "AI Describe" on toolbar
  3. Review side-by-side dialog (seller text left, AI result right)
  4. Edit if needed, click Accept
  5. Description written to column E

The AI client (ai_client.py) is designed for reuse. The generic chat_completion() function can be called by future features (price analysis, sourcing assistance) without modification.


Server-Side ODS Support

Pure Go ODS library at internal/ods/ for server-side spreadsheet generation. No headless LibreOffice dependency -- ODS is a ZIP of XML files.

Library (internal/ods/)

  • ods.go -- types: Workbook, Sheet, Column, Row, Cell, CellType
  • writer.go -- generates valid ODS ZIP archives
  • reader.go -- parses ODS back to Go structs
  • ods_test.go -- 10 round-trip tests

ODS Endpoints

Method Path Description
GET /api/items/export.ods Items as ODS
GET /api/items/template.ods Blank import template
POST /api/items/import.ods Import from ODS
GET /api/items/{pn}/bom/export.ods BOM as formatted ODS
GET /api/projects/{code}/sheet.ods Multi-sheet project workbook
POST /api/sheets/diff Upload ODS, return JSON diff

Build and Install

make build-calc-oxt     # zip pkg/calc/ into silo-calc.oxt
make install-calc       # unopkg add silo-calc.oxt
make uninstall-calc     # unopkg remove io.kindredsystems.silo.calc
make test-calc          # python3 -m unittest (31 tests)

Implementation Status

Component Status Notes
Extension skeleton Done manifest, description, Addons.xcu, ProtocolHandler.xcu
SiloClient Done HTTP client adapted from FreeCAD workbench
Settings Done JSON persistence, env var fallbacks
Login dialog Done Two-step username/password
Settings dialog Done API URL, token, SSL, OpenRouter fields
Pull BOM Done Full column set, hidden groups, hash tracking
Pull Project Done Items sheet + BOM sheet
Push Done Create/update, auto project tagging, conflict detection
Completion wizard Done 3-step with PN conflict resolution
AI description Done OpenRouter client, review dialog, toolbar button
Refresh Stub Placeholder only
Go ODS library Done Writer, reader, 10 round-trip tests
ODS endpoints Done 6 handlers registered
Makefile targets Done build, install, uninstall, test, clean

Known Issues

  • Refresh command is a placeholder (shows "coming soon")
  • No integration tests with a running Silo instance yet
  • completion_wizard.py uses simple input boxes instead of proper list dialogs
  • Push does not yet handle BOM relationship creation (item fields only)

Testing

31 unit tests in pkg/calc/tests/test_basics.py, runnable without UNO or network access:

  • TestSheetFormat (7) -- column indices, headers, sheet type detection
  • TestSyncEngine (9) -- hashing, classification, diff, conflict detection
  • TestSettings (3) -- load/save/auth
  • TestProjectFiles (3) -- path resolution, read/write
  • TestAIClient (9) -- constants, configuration, error handling
$ python3 -m unittest pkg/calc/tests/test_basics.py -v
Ran 31 tests in 0.031s
OK