signalsafe-tree-spec (Python)
Current source and planned customer-subdomain impact: current-state summary.
Python implementation of the TreeSpec wire contract: Pydantic models, parsing, lint, patch helpers, and constants. Backend counterpart to @signalsafe/tree-spec on npm.
| PyPI distribution name | signalsafe-tree-spec |
| Import path | tree_spec |
| GitHub | SignalSafeSoftware/tree-spec |
| Python | 3.12+ (requires-python >=3.12,<4.0) |
| Runtime dependency | Pydantic v2 (pydantic>=2.11.3,<3) |
License: MIT — see LICENSE. See SECURITY.md for vulnerability reporting.
What this package does
- Validate and parse TreeSpec wire JSON into typed Pydantic models (
TreeSpec,Node,Transition, …). - Lint wire payloads (
lint_tree_spec) with structured issues, including duplicate choices, invalid references, unreachable nodes, and reachable paths that cannot reachEND. - Build wire documents programmatically (
TreeSpecBuilder). - Apply JSON patches to wire dicts (
apply_patch_to_spec_dict). - Expose wire constants (
END_NODE_ID,TREESPEC_WIRE_VERSION).
See docs/compatibility.md for how unknown JSON fields are handled (extra="ignore") and how that compares to TypeScript compile/decompile.
What this package does not do
- HTTP APIs, authentication, persistence, or training UI.
- Scenario simulation (use
@signalsafe/simulator-core/simulator-reactin TypeScript stacks). - Graph editor UI (use
@signalsafe/tree-spec-editor-*packages). - General sandboxing or authorization — contract validation only; host apps decide trust and access control.
Install
pip install signalsafe-tree-spec
Development (this repo uses uv):
uv sync --extra dev
uv run pytest
Distribution name vs import path
pip install signalsafe-tree-spec
import tree_spec
from tree_spec import TreeSpec, lint_tree_spec, TreeSpecBuilder
Install the PyPI distribution signalsafe-tree-spec; import its generic tree_spec package.
Quick start
from tree_spec import (
END_NODE_ID,
TREESPEC_WIRE_VERSION,
TreeSpec,
TreeSpecBuilder,
lint_tree_spec,
)
wire = {
"wire_version": TREESPEC_WIRE_VERSION,
"start_node": "start",
"nodes": {
"start": {
"type": "prompt",
"prompt": "Verify the sender before clicking?",
"choices": [{"id": "inspect", "label": "Inspect sender"}],
}
},
"transitions": [
{"from": ["start", "inspect"], "to": END_NODE_ID, "outcome": "safe"},
],
}
issues = lint_tree_spec(wire)
assert not issues
spec = TreeSpec.model_validate(wire)
builder = TreeSpecBuilder()
# builder.add_node(...) — see tests/ for full builder flows
Public API
All symbols below are exported from the top-level tree_spec package:
| Category | Symbols |
|---|---|
| Constants | END_NODE_ID, TREESPEC_WIRE_VERSION |
| Models | TreeSpec, Node, Transition, Choice, Delta, MicroFeedback, ABMeta, ABVariant, … |
| Lint | lint_tree_spec, TreeSpecIssue (level/severity, stable code, optional path) |
| Builder | TreeSpecBuilder, TreeSpecError |
| Patch | apply_patch_to_spec_dict, PatchApplyError, PatchDict, ReplacePatch, … |
The top-level tree_spec package exposes common helpers; submodules such as tree_spec.models and tree_spec.patch remain available.
Wire contract (high level)
wire_version: optional; omit for implicit v1. ConstantTREESPEC_WIRE_VERSIONdocuments the current version string.start_node: entry node id.nodes: map of node id → node object (type,prompt,choicesor legacyoptions, optionalrender_hints).transitions: list of{ from: [nodeId, choiceId], to, outcome? }. Terminal transitions targetEND_NODE_IDand requireoutcome._meta: optional tree-level metadata (for example graph-editor viewport persisted by editor packages).
Legacy payloads may use options instead of choices and legacy terminal ids; both implementations normalize these to canonical choices and END on read. Python lint validates the wire shape your backend accepts.
Python / TypeScript parity
| Concern | Python (python/) |
TypeScript (@signalsafe/tree-spec) |
|---|---|---|
| Wire models & lint | Pydantic models, lint_tree_spec |
TreeSpecWire, lintTreeSpecWire, lintTreeSpecGraph |
| Authoring graph compile | — | compileTreeSpec / decompileTreeSpec |
| Cross-language fixtures | Share JSON fixtures in your product repo or CI | Same |
Keep fixture JSON in sync when changing wire rules in either language. Graph
diagnostics use the same canonical codes and JSON-like paths in both languages;
Python exposes the legacy level field and the equivalent read-only severity
property. Full compile/decompile parity lives in TypeScript today; Python
focuses on validation, lint, builder, and patch flows used by backends.
Development
uv sync --extra dev
uv run pytest
uv run ruff check .
uv run python -m build
uv run python scripts/smoke_package.py
Security
See SECURITY.md. TreeSpec parsing is contract validation, not a sandbox. Validate and authorize TreeSpec JSON in your application layer before treating content as trusted.
Changelog and releases
Related packages
@signalsafe/tree-spec— TypeScript wire contract and compile/lint.tree-spec-editor-*— authoring UI (TypeScript/React).
Python 0.4 migration
Replace former product-specific imports with tree_spec (including submodules).
The PyPI distribution remains signalsafe-tree-spec; upgrade consumers to 0.4.x.
No compatibility alias is provided.
Source layout
Runtime code and the packaged version/typing markers live in
src/tree_spec/. Tests, developer scripts and release metadata
remain outside src/. Run uv sync --frozen --extra dev before local checks;
tests use the installed editable package rather than adding src to PYTHONPATH.
Wheel and source archives are built into dist/.
Release preparation
The maintained source prepares Python 0.4.4 alongside npm 0.4.4. The tree_spec namespace owns the current Python API; the standalone deliveryplus_tree_spec repository is retired. See the coordinated release state and release gates. No publication or consumer adoption is implied by this version change.
Metadata
Release files for signalsafe-tree-spec 0.4.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| signalsafe_tree_spec-0.4.4.tar.gz | 13.2 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| signalsafe_tree_spec-0.4.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 28.6 kB
Release files / signalsafe_tree_spec-0.4.4.tar.gz
| Download URL | signalsafe_tree_spec-0.4.4.tar.gz |
|---|---|
| Size | 13.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f476cc9928567bf9fe1de384a9cfa0a399a784038b1de1d2ee4cd6ed0ba42273
|
|
BLAKE2b-256 checksum How to use checksums |
8afd874758d42d7bc7c7df3c9120d050f1f5447f9794897176b72546d4ff0868
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / signalsafe_tree_spec-0.4.4-py3-none-any.whl
| Download URL | signalsafe_tree_spec-0.4.4-py3-none-any.whl |
|---|---|
| Size | 15.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2a7dd7a06999dd1653b6e159e4310acabe772910223230e52d47dce35b98c462
|
|
BLAKE2b-256 checksum How to use checksums |
0935cb1bde71ebb5f32706f1b8731550541d286310e9da74eeb8ea6b2f65bafb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Security for signalsafe-tree-spec 0.4.4
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.