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
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:
- Category -- select from schema categories (F01-X08)
- Description -- required text, with AI generation offer when blank
- 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
- Paste seller description into column F
- Click "AI Describe" on toolbar
- Review side-by-side dialog (seller text left, AI result right)
- Edit if needed, click Accept
- 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, CellTypewriter.go-- generates valid ODS ZIP archivesreader.go-- parses ODS back to Go structsods_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.pyuses 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