signalsafe-tree-spec (Python)
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 | deliveryplus_tree_spec (stable; historical name) |
| GitHub | SignalSafeSoftware/tree-spec-python |
| 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 deliveryplus_tree_spec
from deliveryplus_tree_spec import TreeSpec, lint_tree_spec, TreeSpecBuilder
The PyPI name (signalsafe-tree-spec) differs from the import path (deliveryplus_tree_spec) for backward compatibility with existing backends.
Quick start
from deliveryplus_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 deliveryplus_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, … |
There are no subpath exports — import from deliveryplus_tree_spec only.
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 (tree-spec-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 flake8 .
uv run python -m build # wheel/sdist smoke — full artifact tests in Batch 6
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).
Metadata
Release files for signalsafe-tree-spec 0.3.0
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.3.0.tar.gz | 14.0 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| signalsafe_tree_spec-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 27.8 kB
Release files / signalsafe_tree_spec-0.3.0.tar.gz
| Download URL | signalsafe_tree_spec-0.3.0.tar.gz |
|---|---|
| Size | 14.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
81bf38d1791cbc862d7b93be3dd22ac6c21fcaf568d1df8872410fd577b3ab4b
|
|
BLAKE2b-256 checksum How to use checksums |
6c34f308839e49ed35b8509289b63f2622bcc860d32b062d2c2618dd97d93d91
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.
Transparency logRelease files / signalsafe_tree_spec-0.3.0-py3-none-any.whl
| Download URL | signalsafe_tree_spec-0.3.0-py3-none-any.whl |
|---|---|
| Size | 13.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f03391a9bd9d5dda8e25ac8248272db12959e7570996e2a4ef5b0c814df9f76f
|
|
BLAKE2b-256 checksum How to use checksums |
cda988b0146293de4ade5049194d1a8b9b6394d30d36932023fc9f158747cc3c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.
Transparency logSecurity for signalsafe-tree-spec 0.3.0
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.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for signalsafe_tree_spec-0.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 8, 2026.
Transparency logA 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.