Documentação
Publishing packages
Build, sign, submit and manage an immutable TDE Package release.
Nesta página
What publishing does
The TDE CLI can publish a signed .tpk directly to the TDE Store. The Website
authenticates the request with a dedicated Publisher Token or GitHub OIDC, verifies the package
and every declared artifact, reserves the package id for your account, and
stores the release as an immutable version.
The Publisher area in Account shows apps and releases, creates the CLI token, registers signing keys, and connects GitHub Actions automation.
Choose what you are publishing
The .tpk package format and Publisher are language-agnostic. The language
requirement depends on how deeply the product integrates with TDE:
| Product | Language | Runtime |
|---|---|---|
| TDE Native App | Rust with tde-app-sdk | Native TDE UI hosted by the app host |
| Shell Widget | Rust with tde-widget-sdk | Isolated widget process outside the desktop process |
| Terminal App | Any language | Runs inside a PTY |
Start a native integration from the official TDE Native App template or Shell Widget template. Terminal applications can use their existing Rust, Go, Python, Node, Zig, or other build; Publisher only requires compatible immutable artifacts and a valid package manifest.
Prerequisites
You need:
- a TDE account and a Publisher Token created in Account → Publisher → CLI Token;
- a unique reverse-DNS package id, such as
dev.example.my-app; - one or more immutable HTTPS artifacts;
- the exact byte size and SHA-256 of each artifact;
- a local 32-byte Ed25519 seed, or the same seed encoded as 64 hexadecimal characters.
Connect the CLI once with tde auth login and paste the token into the hidden
prompt. The token is encrypted in the TDE vault, backed by the OS keyring on a
desktop or an owner-only key file on a headless host, and can be rotated or revoked from the
Account page. TDE_PUBLISHER_TOKEN overrides the saved token. Requests go to
https://tde.sh by default; TDE_SITE_URL can select another Website deployment.
Create the package manifest
From the application's repository:
tde package init --id dev.example.my-app --name "My App"This creates .tde/package.toml. Replace the sample artifact URL, checksum and
size before validating it:
schema_version = 1
[app]
id = "dev.example.my-app"
name = "My App"
version = "1.0.0"
description = "A concise description"
publisher = "Example Developer"
license = "MIT"
homepage = "https://example.dev/my-app"
repository = "https://github.com/example/my-app"
exec = "my-app"
args = []
category = "Utilities"
[[artifacts]]
os = "linux"
arch = "x86_64"
url = "https://github.com/example/my-app/releases/download/v1.0.0/my-app-linux-x86_64.tar.gz"
sha256 = "<64 lowercase hexadecimal characters>"
size = 1234567
[requirements]
system_packages = []
[permissions]
capabilities = []
[config]
paths = []
[uninstall]
owned_paths = ["bin/my-app"]
[update]
channel = "stable"Add another [[artifacts]] block for each supported combination of linux or
macos with x86_64 or aarch64. Artifact URLs must stay on HTTPS, including
redirects. The Website downloads each artifact and requires its actual size and
SHA-256 to match the declaration.
The manifest is declarative and fail-closed. Shell commands, scripts,
preinstall, postinstall, hooks and unknown capabilities are rejected; there
is no force flag.
Validate, pack and sign
tde package validate .tde/package.toml
tde package pack --manifest .tde/package.toml --out dist/my-app-1.0.0.tpk
tde package sign dist/my-app-1.0.0.tpk --key ~/.config/tde/publisher.ed25519
tde package verify dist/my-app-1.0.0.tpkThe key file contains exactly the 32 raw seed bytes. In CI-like local automation, a 64-character hexadecimal seed can be supplied without writing a key file:
export TDE_SIGNING_KEY='<64 hex characters>'
tde package sign dist/my-app-1.0.0.tpk --key-env TDE_SIGNING_KEYThe recommended flow generates the key locally, registers only its public half,
and stores the private seed in the encrypted TDE vault. The latest generated
key becomes the default for tde package sign:
tde package keys generate --name "Release laptop"
tde package keys list
tde package sign dist/my-app-1.0.0.tpk
tde package sign dist/my-app-1.0.0.tpk --key-id <fingerprint>
tde package keys revoke <fingerprint> --reason "Device retired"Do not commit the seed or place it inside the .tpk. The public key is embedded
in signatures/publisher.ed25519; the private seed never leaves your machine.
Publish and follow review
tde auth login
tde auth status
tde package publish dist/my-app-1.0.0.tpk
tde package status <submission-id>
tde package releases --package dev.example.my-appThe first release of a package enters pending_review. The package id is then
owned by your TDE account, so another account cannot publish under the same id.
After approval, updates signed by a key owned by the same account are approved
automatically when they request the same capabilities or fewer. Adding a
capability returns the release to review.
| Status | Meaning |
|---|---|
pending_review | Waiting for TDE review; not yet accepted by the Store |
approved | Accepted and carrying a TDE Store Ed25519 attestation |
rejected | Review refused; inspect review_note in the status response |
yanked | Kept in release history but unavailable for new installs |
revoked | Permanently blocked because of a security incident |
Published versions are immutable. Repeating the exact same submission is safe
and returns the existing release, but changing the bytes of an existing
package id + version is rejected. Increment the semantic version and publish
a new .tpk instead.
All package commands support the global --json option for stable structured
output:
tde --json package publish dist/my-app-1.0.0.tpk
tde --json package status <submission-id>
tde --json package releases --package dev.example.my-appYank a release
Yanking stops new installs without deleting history or allowing the version to be replaced:
tde package yank dev.example.my-app 1.0.0
tde package unyank dev.example.my-app 1.0.0Yank is idempotent. Publish a higher fixed version rather than trying to reuse the yanked version number.
For a compromised release, revoke it permanently and provide an advisory:
tde package revoke dev.example.my-app 1.0.0 --reason "Compromised upstream artifact" --confirm-package-id dev.example.my-appGitHub Actions without a permanent secret
In Account → Publisher → Automation, connect the numeric GitHub repository
id, package id, trusted workflow reference, and allowed ref pattern. Then grant
the workflow id-token: write and publish with --oidc github:
name: Release
on:
push:
tags: ["v*"]
permissions:
contents: read
id-token: write
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and pack
run: |
tde package pack --out dist/app.tpk
- name: Publish with GitHub identity
run: tde package publish dist/app.tpk --oidc githubThe CLI requests a GitHub OIDC identity, exchanges it for a ten-minute, package-bound TDE credential, creates an ephemeral Ed25519 signing key in memory, publishes, and discards the private key. No Publisher Token or signing seed is stored in GitHub secrets. Tokens are replay-protected and the Website checks repository id, exact workflow identity, and Git ref.
Validation limits and common failures
| Failure | What to check |
|---|---|
| Publisher Token is required | Run tde auth login or set TDE_PUBLISHER_TOKEN |
| Publisher signature is required | Run tde package sign, then tde package verify |
| Artifact size/checksum mismatch | Recalculate both from the exact bytes served by the HTTPS URL |
| Namespace belongs to another publisher | Choose an id you own; package ids cannot be transferred through the CLI today |
| Published versions are immutable | Increment app.version, repack and sign again |
| Pending review after an update | The release is new or requests a capability the last approved version did not have |
| Too many submissions | Wait for the Retry-After interval before retrying |
A .tpk upload is limited to 8 MiB and 64 archive members. Downloaded
artifacts are limited to 1 GiB each. Archive paths, duplicate entries, checksum
coverage and compression ratios are validated before the release is stored.
Trust chain
An approved Store release has three independent checks:
- the
.tpkchecksums cover every non-signature member; - the publisher's Ed25519 signature covers the canonical manifest and checksums;
- the TDE Store attestation binds the package id, version and exact package hash to the review decision.
The Store public key is available from
GET /api/v1/store/attestation-key.
An attestation proves which bytes the Store approved; capabilities still follow
the Package Engine and broker policy.
Ownership and collaborators
Publishing without an owner option creates a personal namespace. Use
--org ORG_ID for an organization namespace. In Account → Publisher → Apps,
Owner and Admin roles can add Admin, Publisher, or Viewer collaborators; only
the Owner can transfer the namespace. Transfer requires typing the exact package
id and never changes the immutable package id or release history.