Installation
Two halves: the otigen binary itself, then the language toolchain for whichever of the four you'll write contracts in. Install both before continuing to the next chapter.
1. The otigen binary
Install (curl one-liner)
The canonical install path is a single command. It detects your platform, downloads the latest signed release from the public mirror, verifies the sha256, drops the binary into ~/.otigen/bin, and appends a marker-wrapped export PATH=… block to your shell rc:
curl -fsSL https://raw.githubusercontent.com/pyde-net/test-releases/main/otigen/install.sh | bash
No gh CLI required, no GITHUB_TOKEN setup, no auth dance — the release mirror at pyde-net/test-releases is public and the install script fetches anonymously over plain curl + the GitHub CDN.
Supported targets: macOS arm64, Linux x86_64, Linux aarch64, Windows x86_64. Windows users run the same script from Git Bash or WSL.
Open a new terminal afterwards (so the PATH update takes effect), then confirm:
otigen --version
otigen 0.1.0 (sha be73970a, release)
The version line carries the git SHA + build profile so two contributors can compare binaries when something looks wrong.
Pin a specific version
curl -fsSL https://raw.githubusercontent.com/pyde-net/test-releases/main/otigen/install.sh \
| bash -s -- --version v0.1.0-alpha.1
Pass either the bare version (v0.1.0-alpha.1) or the full mirror tag (otigen-v0.1.0-alpha.1) — both are accepted. Useful for testing, rollback, or reproducibility; pre-release tags work too.
Update
Easiest: let the CLI do it.
otigen update # latest
otigen update --check # poll without side effect (exit 1 = drift)
otigen update wraps the canonical curl one-liner so you don't have to dig the URL out each time. Same script, same target detection, same sigstore verification.
If you don't have otigen on PATH yet (fresh box, broken install), re-run the canonical one-liner directly:
curl -fsSL https://raw.githubusercontent.com/pyde-net/test-releases/main/otigen/install.sh | bash
Idempotent — re-running over an up-to-date install is a no-op on the shell rc.
Uninstall
curl -fsSL https://raw.githubusercontent.com/pyde-net/test-releases/main/otigen/install.sh \
| bash -s -- --uninstall
Removes the binary, strips the marker-wrapped PATH block from every shell rc that has it (~/.zshrc, ~/.bashrc, ~/.bash_profile, ~/.config/fish/config.fish are all scanned), and rmdirs ~/.otigen/bin if empty.
Install-script flags
Pass any of these via bash -s -- <FLAGS>:
| Flag | What it does |
|---|---|
--update | Explicit alias for the default install-or-replace behavior. |
--uninstall | Remove binary + clean shell rc + drop empty install dir. |
--version <TAG> | Pin a specific release tag instead of the latest. Accepts vX.Y.Z or otigen-vX.Y.Z. |
--prefix <DIR> | Install location override. Default ~/.otigen/bin; also honours OTIGEN_INSTALL_DIR env var. |
--no-modify-path | Skip the shell-rc PATH edit. For users with managed dotfile repos. |
--no-verify-sig | Skip sigstore-keyless signature verification of the downloaded asset (default: verify when cosign is on PATH). |
--check-only | Dry run — print what the script would do and exit. Works with any mode. |
-h / --help | Full catalog. |
Manual download
If you'd rather skip the script, grab the per-platform tarball directly from the public mirror's release page:
# Replace v0.1.0-alpha.1 with the current release tag, and the target triple
# (aarch64-apple-darwin / x86_64-unknown-linux-gnu / aarch64-unknown-linux-gnu /
# x86_64-pc-windows-msvc) with your platform. The mirror prefixes every
# otigen release tag with `otigen-`, so the lookup is `otigen-<tag>`.
gh release download otigen-v0.1.0-alpha.1 --repo pyde-net/test-releases \
--pattern 'otigen-v0.1.0-alpha.1-aarch64-apple-darwin.tar.gz' \
--pattern 'otigen-v0.1.0-alpha.1-aarch64-apple-darwin.tar.gz.sha256'
shasum -a 256 -c otigen-v0.1.0-alpha.1-aarch64-apple-darwin.tar.gz.sha256
tar xzf otigen-v0.1.0-alpha.1-aarch64-apple-darwin.tar.gz
sudo install -m 0755 \
otigen-v0.1.0-alpha.1-aarch64-apple-darwin/otigen \
/usr/local/bin/
Anonymous curl -L against the asset's browser_download_url works the same way for users without gh installed.
Every release publishes binaries for all four platforms, each accompanied by:
.sha256— checksum (auto-verified by the install script)..sig+.pem— sigstore-keyless OIDC signature + certificate. The install script doesn't currently verify these (cosign is an optional install on the user side); manual verification flow lives in the mirror README and is normatively specified inOTIGEN_BINARY_SPEC §11.4.
Build from source
For contributors and bleeding-edge users. While the source repos are private during pre-mainnet engineering, sibling-clone access requires Contents:read on each:
git clone https://github.com/pyde-net/otigen
git clone https://github.com/pyde-net/engine # sibling — path-dep'd by otigen-cli
git clone https://github.com/pyde-net/pyde-crypto # sibling — also path-dep'd
cd otigen
cargo build --release -p otigen-cli
sudo install target/release/otigen /usr/local/bin/
Installs to /usr/local/bin/otigen. Requires Rust ≥ 1.93 (cranelift transitive dep). The three sibling repos are needed because the otigen workspace path-deps into both engine/ and pyde-crypto/.
Once the source repo flips public for v1, the same make install (or cargo install --path crates/otigen-cli) flow works from a public clone with no auth.
Note: make install and cargo install --path … write to ~/.cargo/bin/otigen (cargo's standard target), not /usr/local/bin/otigen. If you've previously used the curl one-liner or the sudo install step above, ~/.cargo/bin must appear earlier on PATH for the new binary to win.
2. Language toolchain
Install only the one(s) you'll use. Each language's Makefile (generated by otigen init or otigen new) has a make check-tools target that verifies the chain is set up correctly.
Rust
# rustup gives you the compiler + the wasm32 target.
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target add wasm32-unknown-unknown
Required version: Rust ≥ 1.93 (matches the rust-version floor in the workspace Cargo.toml; raised from 1.87 when wasmtime 45's cranelift transitive deps pushed the MSRV up).
Verify:
rustup show | grep -E "active toolchain|wasm32"
Common errors: see install-gotchas — TL;DR: forget the wasm32-unknown-unknown target and you get cryptic linker errors at the first cargo build.
TinyGo
# macOS
brew tap tinygo-org/tools
brew install tinygo go binaryen
# Linux (apt)
apt install tinygo golang binaryen
Three packages are required:
- TinyGo — the wasm32 compiler.
- Go — TinyGo bundles its own Go compiler fork but also needs a standard Go install for module resolution. Without it,
tinygo versionreports(using go version <unknown>)and module resolution misbehaves silently. - binaryen — ships
wasm-opt, which TinyGo invokes for size optimisation under the-opt=zflag the otigen scaffold uses. Without it, any compile path (otigen build/otigen test/otigen check) fails fast with a platform-tagged install hint (ToolchainMissing: TinyGo requires `wasm-opt` (binaryen) for size optimisation).
Required versions: TinyGo ≥ 0.41, Go ≥ 1.21 (for //go:wasmimport), binaryen ≥ 116 (anything wasm-opt --version reports works in practice).
The wasm-unknown target landed in TinyGo 0.31, but the otigen Go scaffold + canonical examples are tested against the 0.41 series — earlier versions hit //go:wasmexport codegen bugs that landed fixes in 0.34 / 0.36 / 0.41. The scaffold's otigen.toml pins tinygo_version = "0.41.0"; older toolchains aren't supported.
Verify:
tinygo version
wasm-opt --version
tinygo version 0.41.1 darwin/arm64 (using go version go1.26.3 and LLVM version 20.1.1)
wasm-opt version 130
Common errors:
brew install tinygo(without the tap) fails with "no available formula." You mustbrew tap tinygo-org/toolsfirst.could not find wasm-opt, set the WASMOPT environment variable to override: binaryen isn't installed.brew install binaryen(macOS) /apt install binaryen(Debian) /pacman -S binaryen(Arch). To point TinyGo at a custom build, setWASMOPT=/path/to/wasm-optin your shell.- First
tinygo buildafterotigen initfails witherror obtaining VCS status: exit status 128if the project dir isn't a git repo. Fix:git init -qinside the project.
AssemblyScript
# macOS
brew install node
# Or any Node ≥ 18 install:
# https://nodejs.org/en/download
# Then, per-project:
cd <project-dir> && npm install
# (uses the local `assemblyscript` devDependency from package.json)
Or install globally:
npm install -g assemblyscript
Required versions: Node ≥ 18, AssemblyScript ≥ 0.28.
Verify:
node --version
asc --version
Common errors:
asc: command not foundafternpm install -g: your npm global prefix isn't on$PATH. Checknpm config get prefixand add<prefix>/bintoPATH. Or use the local install vianpm run build.- Compile fails with
env.abort import is forbidden: someone removed theuse: ["abort=..."]line inasconfig.json. See Debugging.
C / C++
# macOS — Apple's bundled clang lacks the wasm32 backend.
# Install brew's LLVM + lld:
brew install llvm lld
# Add to your shell profile (~/.zshrc or similar):
echo 'export PATH="/opt/homebrew/opt/llvm/bin:/opt/homebrew/opt/lld/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
# Linux: clang + lld from apt usually ships wasm32 ready.
apt install clang lld
Required components: clang with the wasm32 backend (verify with clang -print-targets | grep wasm32) AND wasm-ld (LLVM's WASM linker, lld package).
Verify:
clang -print-targets | grep wasm32
which wasm-ld
Common errors:
error: unable to create target: 'No available targets are compatible with triple "wasm32"': you're using Apple's/usr/bin/clangwhich lacks the wasm32 backend. Install brew's LLVM and updatePATH.clang: error: unable to execute command: posix_spawn failed: No such file or directorywhen linking:wasm-ldis missing.brew install lldseparately — it's NOT pulled in bybrew install llvm.MakefileusesclangfromPATH. Ifwhich clangresolves to Apple's, the build fails. Either re-order yourPATHor override per-build:make CC=/opt/homebrew/opt/llvm/bin/clang build.
3. Verify everything together
The fastest end-to-end smoke test — otigen test auto-invokes the per-language compiler before running the suite, so a single command covers build + test:
otigen new smoke-test --lang rust --from counter
cd smoke-test
otigen test
→ Compiling (rust) — cargo build --target wasm32-unknown-unknown --release
✓ Compiled → ./target/wasm32-unknown-unknown/release/smoke_test.wasm
Running 3 tests in ./tests/contract.test.toml (via engine)
✓ get_returns_zero_initially (29.55 ms)
✓ increment_advances_by_one (7.72 ms)
✓ three_increments_yield_three (6.82 ms)
test result: ok. 3 passed; 0 failed; 0 skipped (3 ran)
First-run timings include the full release compile (~10–30 s on a small Rust contract); subsequent runs hit cargo's incremental cache and finish in <1 s.
If you get that output, you're ready for the next chapter. If not, the error message tells you which piece is missing — most install issues route to a command not found or a clear missing-target message; cross-check against the per-language notes above.
Reference
- Full per-language install gotchas with troubleshooting steps: Debugging — installation errors.
- Toolchain pinning for reproducible builds: each project's
otigen.tomlrecordsrust_channel/tinygo_version/asc_version/clang_version. The chain doesn't enforce these, but your team should. For team-wide enforcement on audit machines,otigen verify --strict-toolchain <addr>cross-checks the bundle's declared toolchain versions against the host's installed compilers and fails on mismatch. - The
make check-toolstarget inside each scaffolded project verifies all four prerequisites are present + correct. - Public release mirror:
pyde-net/test-releases— README covers the tag convention, manual sigstore verification, and the canonical surfaces for every Pyde toolchain.