Package Manager
tulpar pkg is the built-in package manager for Tulpar. It manages
project dependencies via a small TOML manifest (tulpar.toml) and
writes a deterministic lockfile (tulpar.lock) on every install so
your tulpar_modules/ tree is reproducible across machines.
The official package registry lives at
pkg.tulparlang.dev — point
[registry] url there in your manifest to install community packages.
Quick start
Section titled “Quick start”# Inside an empty project directorytulpar pkg init my-api
# Add a local-path dependency (development)tulpar pkg add greeter@path:../greeter
# Add a single-file URL dependencytulpar pkg add lodash@url:http://my-cdn/lodash.tpr
# Add a semver-style registry dependency (requires [registry] url in tulpar.toml)tulpar pkg add wings@1.2.3
# Vendor everything into ./tulpar_modulestulpar pkg installAfter tulpar pkg install, the consumer can import "greeter" and the
runtime resolves it from tulpar_modules/greeter/greeter.tpr.
Manifest format
Section titled “Manifest format”tulpar.toml is a deliberately tiny TOML subset — string values only,
top-level keys plus [registry] and [dependencies] tables.
name = "my-api"version = "0.1.0"description = "Tulpar HTTP API example"author = "Hamza"license = "MIT"
[registry]url = "https://api.pkg.tulparlang.dev" # the API base; this is also the default
[dependencies]wings = "1.2.3" # registrygreeter = "path:../greeter" # local sibling dirlodash = "url:http://cdn/lodash.tpr" # single-file URLVersion specs
Section titled “Version specs”| Form | Meaning |
|---|---|
path:./local/dir | Recursively copy *.tpr from a local directory. |
url:http://example.com/x.tpr | Plain HTTP fetch of a single .tpr file. |
1.2.3 | Exact version from the registry. |
^1.2.3 / ~1.2.3 | Semver range — caret (within major) / tilde (within minor). |
>=1.0,<2.0 / * / latest | Comparator/compound range, or highest published version. |
For an exact version Tulpar hits the registry directly. For a range
(^, ~, a </>/= comparator, a comma-compound, or */latest) it
first fetches the package’s published versions from
<registry>/v1/packages/<name>, picks the highest one that satisfies the
range, then downloads
<registry>/v1/packages/<name>/versions/<version>/source.
A registry version spec requires a registry URL — [registry] url = "..."
in the manifest, the --registry flag, or the TULPAR_REGISTRY env var
(default https://api.pkg.tulparlang.dev). https:// URLs require Tulpar to
be built with OpenSSL (pacman -S mingw-w64-x86_64-openssl on MSYS2).
Lockfile
Section titled “Lockfile”After every successful pkg install, Tulpar writes tulpar.lock next
to your manifest:
# tulpar.lock — auto-generated by `tulpar pkg install`.# DO NOT EDIT. Commit alongside tulpar.toml so re-installs are reproducible.
[resolved]wings = "https://api.pkg.tulparlang.dev/v1/packages/wings/versions/1.2.3/source"greeter = "path:../greeter"lodash = "url:http://cdn/lodash.tpr"The lockfile records the fully resolved URL or path plus a SHA-256
of the downloaded bytes for each dependency, so a re-install on another
machine fetches the exact same bytes — even if the registry’s latest
pointer moves. A re-install that finds the same URL serving a different
SHA-256 than the lockfile records is refused rather than silently
overwritten.
Module resolution
Section titled “Module resolution”When the AOT compiler sees import "name", it tries (in order):
- The embedded standard library (
wings,router,http_client,orm,test, …). - A bundle-local sibling —
<importing-file's-dir>/name.tpr— so a multi-file package’s internal imports resolve to its own files. - The literal path
./name. - The literal path with
.tprappended (./name.tpr). ./tulpar_modules/<name>/<name>.tpr— the vendored entry-point convention../tulpar_modules/<name>.tpr— single-file vendor.
That ordering means the embedded stdlib names (wings, orm, …) always win
— you can’t shadow wings with a local wings.tpr — and a vendored package
in tulpar_modules/ is the fallback for everything else.
Subcommands
Section titled “Subcommands”| Command | Effect |
|---|---|
tulpar pkg init [name] | Create a starter tulpar.toml (refuses to overwrite). |
tulpar pkg list | Print package metadata + dependencies. |
tulpar pkg add <name>[@<ver-spec>] | Add or update a manifest dependency line. |
tulpar pkg remove <name> | Drop a manifest dependency line. |
tulpar pkg install | Vendor every dep into tulpar_modules/ + write tulpar.lock. |
tulpar pkg search <query> | Search the registry catalog by name/description. |
tulpar pkg info <name> | Print a package’s registry metadata + published versions. |
tulpar pkg publish [--dry-run] | Bundle the project’s sources and POST them to the registry. |
Publishing
Section titled “Publishing”tulpar pkg publish bundles every .tpr source in your project and uploads
it to the registry under your manifest’s name + version (both required).
Authentication is a bearer token — pass --token <tok> or set
TULPAR_PUBLISH_TOKEN:
export TULPAR_PUBLISH_TOKEN="…"tulpar pkg publish --dry-run # bundle + show what would ship, no uploadtulpar pkg publish # POST to <registry>/v1/publishThe registry target follows the same resolution as installs (--registry
flag → [registry] url → TULPAR_REGISTRY → the default
https://api.pkg.tulparlang.dev). --dry-run skips the POST so you can
inspect the bundle without a token.
Roadmap
Section titled “Roadmap”- Multi-file packages via tar/zip extract from registry URLs.
- Package signing (the lockfile already records a SHA-256 per dependency).