CD and Distribution Rulebook
This document captures the publication model for Meerkat binaries and SDKs (rkat, rkat-rpc, rkat-rest, rkat-mcp, Python SDK,
and TypeScript SDK).
Goals
- Publish a single source project to multiple ecosystems.
- Keep runtime binaries available for macOS/Linux/Windows users.
- Let Python (
pip/uv) and Node (npm) users install from package managers without needing a Rust toolchain. - Preserve reproducible releases with strong version/contract checks.
Release Baseline
Run these before release:make release-preflightmake verify-version-paritymake verify-schema-freshness
make release-dry-run
Cargo.tomlworkspace versionsdks/python/pyproject.tomlversionsdks/typescript/package.jsonversion- generated contract artifacts
Distribution Topology
1) Runtime binaries (GitHub Releases)
Release artifacts are built for each surface binary:rkat(CLI)rkat-rpcrkat-restrkat-mcp
x86_64-unknown-linux-gnuaarch64-unknown-linux-gnuaarch64-apple-darwinx86_64-apple-darwinx86_64-pc-windows-msvc
rkat-rpc-vX.Y.Z-x86_64-apple-darwin.tar.gzrkat-rest-vX.Y.Z-x86_64-unknown-linux-gnu.zip
dist/checksums.sha256dist/index.json
2) Python SDK distribution
Package behavior should be pure-Python with optional runtime auto-download:pip install meerkat-sdk(anduvequivalent)- Package should not require Rust/toolchain locally
- First connect:
- If
MEERKAT_BIN_PATHis set, use it - Otherwise, download correct
rkat-rpcbinary for platform/version from GitHub Releases - Cache in user-local location (
~/.cache/meerkat/bin/...)
- If
3) TypeScript SDK distribution
npm install @rkat/sdk- The SDK package remains JS-only; no native modules.
MeerkatClientresolves server binary with the same strategy:- env override path first
- otherwise download platform binary from GitHub Releases
claude mcp add, npx), provide a CLI entrypoint package:
npx @meerkat/mcp(or equivalent) launches the JS shim- shim resolves local override or downloaded
rkat-mcp
GitHub Actions Design (single-release flow)
Job 1 — Validate
make cimake verify-version-parity
Job 2 — Build matrix
- Use GH hosted runners for:
macos-latestubuntu-latestwindows-latest
- Build release binaries for all required targets.
Job 3 — Publish GitHub release
- Create release tag
vX.Y.Z - Upload compiled binaries and checksum/index files.
Job 4 — Publish crates (optional by timeline)
cargo release ...(or equivalent scripted sequence)- Rust crates should be published first or concurrently after checks pass.
- Dry-run mode: run the same validation/build path without registry writes using manual dispatch input
registry_dry_run=true.
Job 5 — Publish language packages
- Publish Python wheel (
meerkat-sdk) from same version - Publish TypeScript package (
@rkat/sdk, optional MCP wrapper package) - Both packages support dry-run behavior in registry publish mode so you can validate metadata/build without actually uploading.
Job 6 — Post-release smoke
- Verify:
pip installsucceedsuv pipvariant worksnpx/ MCP command resolves and launches binary for a platform from release assets
Account / credential configuration
You only mentioned Cargo is already configured; Pip/npm still require separate credentials.Rust (already configured)
- Keep your Cargo token (already set).
- Ensure API token has permission to publish all crates.
PyPI
- Create/import a PyPI account and API token.
- Store token in CI as
PYPI_API_TOKEN(orpypi-tokenequivalent secret for your CI tool). - Use API token auth in publishing:
- user name:
__token__ - password: token value
- user name:
- Optional separate TestPyPI flow with separate token.
npm
- Create npm account with publish rights to package scope (
@meerkatorg/user scope). - In CI, store token as
NPM_TOKEN. - Configure automation profile:
npm config set //registry.npmjs.org/:_authToken=${NPM_TOKEN}
- Ensure package versions are always incremented.
MCP + CLI ergonomics decision
- Keep Python/TypeScript SDKs as pure clients.
- Keep runtime downloads in SDK layers (or thin wrapper binaries/entrypoints), not in end-user binaries.
- Surface contracts stay stable because transport endpoints are unchanged; only bootstrap/packaging changes.
Hard constraints to enforce
- Never publish mismatched versions:
- Rust workspace, Python package, TypeScript package, contract artifacts.
- Release only from tagged versions.
- Never publish SDKs that point to a commit with stale schema/generator artifacts.
- Keep runtime binary names and entrypoints stable per surface.
- Keep checksum and index files for deterministic, auditable consumers.
Minimal checklist for each release
-
make release-preflight - tag release (
git tag -a vX.Y.Z) - build + upload all binary assets in release workflow
- publish crates
- publish Python SDK
- publish TypeScript SDK (and MCP entrypoint package if present)
- confirm smoke checks (
pip,uv,npx) across at least one platform
Current state note
This is a plan/rulebook currently. Code and workflows should follow this sequence with minimal surface-area, no behavior changes to runtime APIs.Registry publish dry-run
- Workflow dispatch inputs:
publish_release_packages(default: false): enable publish job.registry_dry_run(default: false): keep publish jobs in dry-run mode.
- Dry-run behavior:
- Rust:
cargo publish --dry-runfor each crate in publish list. - Python:
python -m twine checkon the built wheel/sdist, no upload. - TypeScript:
npm publish --dry-run.
- Rust:
- Local equivalent:
make release-dry-run
- Example:
gh workflow run release.yml -f publish_release_packages=true -f registry_dry_run=true
