rspyts-cli 3.0.0

Compiler and build orchestrator for rspyts
Documentation

rspyts-cli

rspyts-cli creates and maintains a Rust application with installable Python and TypeScript source projects beside it. The installed executable is named rspyts.

Install

cargo install rspyts-cli --locked
rustup target add wasm32-unknown-unknown

rspyts requires Rust 1.88 or newer. Generation invokes Cargo for the native and wasm32-unknown-unknown builds. It does not invoke Python, Node.js, npm, or the TypeScript compiler.

Create an application

rspyts init path/to/hello-rspyts --version 1.2.3

The destination must not exist. Its last path component becomes the Cargo package name and must contain lower-case ASCII letters, numbers, and single hyphens. It must start with a letter and cannot end with a hyphen. The version must be valid semantic versioning and defaults to 0.1.0.

The same name is used for the npm package. Each hyphen becomes _ in the default Python import package:

Project name Python import npm import
hello-rspyts hello_rspyts hello-rspyts

Initialization writes the Rust greeting example, rspyts.toml, a Python source project under src-py, and a TypeScript source project under src-ts. The same version is written to Cargo.toml, src-py/pyproject.toml, and src-ts/package.json. Manifests and root language entrypoints are scaffolded once.

Configure an application

rspyts.toml is the authority for application selection and generated-file ownership. It lives next to the application’s Cargo.toml.

The editable portion is [application]:

[application]
# Override the public application name.
# Defaults to the adjacent Cargo package name.
# name = "my-application"

# Link other library packages from this Cargo workspace.
# The adjacent package is always linked.
# additional_packages = ["my-shared-api"]

# Override the Python import package.
# Defaults to the application name with each hyphen changed to `_`.
# python_package = "my_application"

# Override the npm package name.
# Defaults to the application name and must match src-ts/package.json.
# typescript_package = "my-application"

# Maintain nested ignore files for generated paths.
# Defaults to true.
# gitignore = false

All five settings are optional.

Setting Default Effect
name Adjacent Cargo package name Selects the public application identity
additional_packages [] Adds named workspace library packages to the same application
python_package Application name with - changed to _ Selects the generated Python import path
typescript_package Application name Selects the generated TypeScript source directory and must match the npm manifest
gitignore true Creates owned ignore files containing every generated path

The remaining tables are maintained by rspyts:

[generated]
source_fingerprint = "..."

[generated.python]
files = ["..."]
native_modules = ["..."]

[generated.typescript]
files = ["..."]

files contains project-relative paths that a future build may overwrite or remove. native_modules stores Python extension basenames because the platform chooses .abi3.so or .pyd. The source fingerprint covers Rust source files, Cargo manifests and locks, the active application settings, and the rspyts generator version.

Do not hand-edit the generated tables. Change the Rust contract or [application], then run rspyts build.

Select an application

build, watch, and check use the same discovery order:

  1. Use the file or directory passed with --config.
  2. Otherwise, use the nearest rspyts.toml in the current directory or an ancestor.
  3. Otherwise, inspect the enclosing Cargo workspace and use its sole rspyts application.

If a workspace contains more than one application, select one explicitly:

rspyts build --config crates/server/rspyts.toml

Passing the application directory is also valid:

rspyts build --config crates/server

Build

rspyts build

A build:

  1. Resolves the adjacent Cargo package and every additional_packages entry.
  2. Compiles an internal bridge as a native library and reads its contract.
  3. Validates names, namespaces, model references, and the user-owned package manifests.
  4. Compiles the same application for WebAssembly.
  5. Renders Python, TypeScript, native, and WebAssembly files in a temporary directory.
  6. Publishes the Python extension under src-py/<package>/native and the Wasm module directly under src-ts/build/<package>/native.
  7. Publishes generated Python, TypeScript, and wasm-bindgen source files into their owned paths.

The JSON report identifies both source roots and public package names:

{
  "status": "ok",
  "pythonSource": "/path/to/hello-rspyts/src-py",
  "typescriptSource": "/path/to/hello-rspyts/src-ts",
  "pythonPackage": "hello_rspyts",
  "typescriptPackage": "hello-rspyts"
}

Both language manifests must declare the same version as the adjacent Cargo package. The Python manifest must declare pydantic; if the contract uses #[rspyts(buffer)], it must also declare numpy. The npm manifest’s name must match the configured TypeScript package. rspyts reports these mismatches but never rewrites either manifest.

Preserve authored files

Only paths from the generated tables are mutable. During publication, rspyts:

  • overwrites generated paths that remain present;
  • removes generated paths no longer produced by the contract;
  • preserves every unlisted file;
  • rejects an unlisted destination collision before mutation;
  • restores the previous generated set and ownership metadata if publication fails.

Text files produced by rspyts begin with an explicit generated-file banner:

=============================================================================
AUTO-GENERATED BY rspyts - DO NOT EDIT.

This file is overwritten by `rspyts build`.
=============================================================================

Comment syntax differs by language. Native extensions and Wasm files are binary and are identified by rspyts.toml instead.

The default nested .gitignore files list exact generated paths. Set gitignore = false and rebuild to remove those ignore files and include generated files in version control.

Watch

rspyts watch

watch builds immediately, then monitors Rust files, Cargo manifests and locks, and [application]. A failed rebuild is printed to standard error, and the watcher continues so the next source change can recover.

Check

rspyts check

check generates the expected application in a temporary directory and compares it with the recorded generated state. It fails when an owned file is modified, missing, unexpectedly retained, or derived from an old source fingerprint. Extra user-owned files do not affect the result.

Use this command in CI after build when generated files are produced during the job, or directly when generated files are included in version control.

Package the language projects

rspyts generates source projects; their ecosystem tools create release archives:

python -m pip wheel --no-deps ./src-py

npm --prefix src-ts install
npm --prefix src-ts run check
npm --prefix src-ts run build
npm pack ./src-ts

The Python project uses PDM’s build backend through pyproject.toml to package the prebuilt native module without a setup script or compiler step. rspyts places the Wasm asset in its final npm output directory, so the npm build script only invokes tsc.

See the repository README for a first project and the example guide for a self-contained application.