Skip to main content

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 reach END.
  • 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-react in 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. Constant TREESPEC_WIRE_VERSION documents the current version string.
  • start_node: entry node id.
  • nodes: map of node id → node object (type, prompt, choices or legacy options, optional render_hints).
  • transitions: list of { from: [nodeId, choiceId], to, outcome? }. Terminal transitions target END_NODE_ID and require outcome.
  • _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

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/.

Metadata

Release files for signalsafe-tree-spec 0.4.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for signalsafe-tree-spec 0.4.3
File Size Uploaded Provenance
signalsafe_tree_spec-0.4.3.tar.gz 13.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for signalsafe-tree-spec 0.4.3
File Interpreter ABI Platform
signalsafe_tree_spec-0.4.3-py3-none-any.whl Python 3 none any Details

Total release size: 28.3 kB

Release files / signalsafe_tree_spec-0.4.3.tar.gz

Download URL signalsafe_tree_spec-0.4.3.tar.gz
Size 13.0 kB
Tags Source
SHA-256 checksum
How to use checksums
163ef624d103eefd0c675723f9cf47993549ef4377ea98188261c394936f5f17
BLAKE2b-256 checksum
How to use checksums
cbe63c787c3f474fd3d153c00cdfa219e95a24b29e49b6e35364dd2f240fbad9
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.3-py3-none-any.whl

Download URL signalsafe_tree_spec-0.4.3-py3-none-any.whl
Size 15.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4672c19d3747052ef65c8e89d52a1f522ac77389ccdab9e9e3534b2e38b96d80
BLAKE2b-256 checksum
How to use checksums
b93290c2328fcc687c067c9573a8474c2730533ec6a563bfbaa487f1d328839a
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.3

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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page