Publish a package
Push a package to api.pkg.tulparlang.dev with the
tulpar pkg publish CLI. No PR, no merge — just a
single command.
1. Install the Tulpar toolchain
The publish CLI ships with the main Tulpar binary. If you don't already have it, see the tulparlang.dev install instructions (Windows installer + Linux/macOS one-liners).
2. Get a publish token
Publishing requires a bearer token configured on the registry server. Currently the registry is in invite-only mode — open a discussion at tulpar-be/discussions to request a token. Once you have one, expose it to the CLI via environment variable:
export TULPAR_PUBLISH_TOKEN=your-token-here
export TULPAR_REGISTRY=https://api.pkg.tulparlang.dev 3. Lay out your package
The CLI walks the current directory for .tpr files
(skipping tulpar_modules/, build*/,
hidden dirs, node_modules) and packages everything
it finds. The only hard rule: a file named
<name>.tpr must exist at the project root —
that's the entry point consumers will import.
name = "my-pkg"
version = "0.1.0"
description = "One-line summary that shows up on the package card."
license = "MIT" func hello() {
print("hello from my-pkg");
} 4. Dry-run, then publish
--dry-run walks the project, builds the bundle,
prints the SHA-256, and stops short of the network call. Always
do this once before the real push so you know what's about to
ship.
tulpar pkg publish --dry-run # preview
tulpar pkg publish # the real thing
On success you'll see HTTP 201 and the package
appears at
pkg.tulparlang.dev/
within a minute (the catalog page caches for 60 seconds).
Versioning rules
- Versions are immutable. Once
(name, version)is published the bytes are pinned forever. A republish of the same pair returnsHTTP 409 Conflict— bump the version intulpar.tomland try again. - Semver is recommended but not enforced. The version string is taken literally; whatever you pass lands in the URL fragment.
- SHA-256 ships in the response. Consumers'
tulpar.lockpins to the digest the registry records, so once a version is out the bytes can't move.
Multi-file packages
If your project has more than one .tpr file, the
CLI auto-bundles them into a .tpkg JSON archive
and the registry serves the bundle as the package source.
Sibling imports inside the bundle resolve naturally:
my-pkg/
├── tulpar.toml
├── my-pkg.tpr # entry — imports siblings
└── helpers/
└── strings.tpr # import "helpers/strings"