Contributing to uniwire¶
Thank you for your interest in uniwire! Contributions of all kinds are welcome: bug reports, examples, symbols, rules, translations, documentation and changes to the format itself.
uniwire has two layers:
- the format: the specification (
docs/SPEC.md), the JSON Schema (schema/uniwire.schema.json) and the type registry (src/uniwire/registry/core.json); - the reference implementation: the
uniwirePython package (model, validation, rules, rendering, bill of materials, code-first API, CLI).
Please read and follow the Code of Conduct. Security issues must be reported privately, see SECURITY.md.
Repository layout¶
| Path | Content |
|---|---|
src/uniwire/ |
the Python library (model, validation, rules, layout, rendering, exports, CLI, LLM tools, MCP server) |
schema/ |
the published JSON Schema, generated from the models |
examples/ |
example documents (examples/code/: examples written with the code-first API) |
tests/ |
the test suite |
docs/ |
the documentation (MkDocs): specification, guides, proposals (docs/uep/) and logo files (docs/brand/assets/), README gallery (docs/gallery/) |
viewer/ |
the web viewer (static site running the library with Pyodide) |
docker/mcp/ |
the official MCP server image |
packages/uniwire-data-iec81346/ |
the optional CC BY-SA 4.0 data package |
evals/llm/ |
evaluation tasks for model-written documents |
Development setup¶
The project uses uv (plain python -m venv and pip work too).
git clone https://github.com/uniwire-dev/uniwire.git
cd uniwire
uv venv
uv pip install -e ".[dev]" -e packages/uniwire-data-iec81346
Python 3.10 or later is required. The dev extra installs pytest, jsonschema, reportlab (PDF output), the
MCP SDK and ruff. No lock file is committed: the commands below run the tools of .venv directly, so they
do not create one (uv run would write a uv.lock).
Running the tests and the linter¶
.venv/bin/python -m pytest -q
.venv/bin/ruff check .
The suite covers the model, validation, rules, rendering, the code-first API, internationalisation and
the published schema. Every example in examples/ is validated against the committed schema and rendered.
Please add or update tests with every change.
Regenerating the JSON Schema¶
The pydantic models in src/uniwire/model/ are the source of truth for the schema. After any model change:
.venv/bin/uniwire schema -o schema/uniwire.schema.json
and commit the regenerated file. A drift test (tests/test_schema.py) and a CI step fail when the
committed schema does not match the models.
Documentation and viewer¶
uv run --no-project --with "mkdocs<2" --with mkdocs-material mkdocs build --strict -d /tmp/uniwire-docs
.venv/bin/python viewer/build.py --out /tmp/uniwire-viewer # then: python -m http.server -d /tmp/uniwire-viewer
The logo files live in docs/brand/assets/ only; the documentation and the viewer build read them from
there.
Adding an example¶
- Write
examples/<name>.uniwire.json(or a Python script underexamples/code/that builds it withuniwire.build). Use the$schemaURLhttps://uniwire.sh/schema/v1/uniwire.schema.json. - Check it:
.venv/bin/uniwire validate examples/<name>.uniwire.jsonthen.venv/bin/uniwire check examples/<name>.uniwire.json. - Render it:
.venv/bin/uniwire render examples/<name>.uniwire.json -f pdf -o out/<name>.pdfand look at the result. - Only publish data you are allowed to share: no personal data, no copyrighted drawings.
Translations¶
uniwire renders in English by default and supports French. To improve or add a language:
- Messages (CLI, validation errors, rule findings, title block and sheet texts) live in the catalog
src/uniwire/i18n.py:ENis the reference, other languages (FR) mirror its keys. A missing key falls back to English.tests/test_i18n.pychecks that the catalogs stay in sync. - Type labels (shown on drawings and in the bill of materials) live in the
labelobject of each type insrc/uniwire/registry/core.json({"en": …, "fr": …}). - Viewer interface: the strings of the web viewer live in
viewer/i18n.js(English, French).
Rendering follows meta.lang of the document; the CLI follows the UNIWIRE_LANG environment variable.
Changing the format: uniwire Enhancement Proposals (UEP)¶
Every change to the format goes through a short public proposal, opened as a GitHub issue with the
Format proposal template (label uep):
- Motivation: which real installations or drawings need it? Describe the use case and, if possible, attach a small anonymised example.
- Proposal: fields, types or link kinds, with JSON examples, and the mapping to CIM / IFC / IEC 61850 SCL where relevant.
- Compatibility: minor versions (1.x) only add optional fields, types or enumeration values; anything that breaks existing files waits for the next major version and ships with a migration function.
- Implementation: the change in the reference library, the schema regenerated, the specification updated, the changelog entry, at least one example or test using it, and the whole test suite green.
Code style¶
- Python ≥ 3.10, type hints everywhere; pydantic v2 models are the source of truth for the schema.
- Keep the renderer deterministic (tests compare structures).
- User-facing text goes through
uniwire.i18n: never hard-code English or French strings. - Keep pull requests focused, and describe user-visible changes in
CHANGELOG.md.
Licensing of contributions¶
By contributing you agree that your code is licensed under the Apache License 2.0 and your specification
text under CC BY 4.0. Contributions to the optional packages/uniwire-data-iec81346 data package are
licensed under CC BY-SA 4.0.