RFD 0013 — Toolchain distribution + oxup toolchain manager
- State: accepted — partially implemented (Stage 0 deployed, Stage 4 merged)
- Opened: 2026-06-01
- Last revised: 2026-06-02
- Decides: how Argon ships to engineer laptops (Mac arm64) + ODE sandbox AMIs (Linux arm64 + x86_64); whether to adopt a rustup-style toolchain manager; the AWS-hosted distribution architecture; the
~/.argon/legacy-install cleanup story. - Status: Implemented — the v0.2 toolchain shipped; this RFD is the design record.
Question
v0.1.0 ships a single ox binary from a homemade install.sh against git clone. For Sharpe-internal v0.2, what’s the install + distribution + toolchain-management story?
Decision
Adopt the rustup-style architecture with an oxup manager binary + argv[0] dispatch, splitting the compiler into four logical tools (oxc / ox / ox-lsp / oxfmt), distributed via AWS S3 + CloudFront at argon.sharpe-dev.com (managed via Pulumi in the shared infra account 285688017134). The user-facing reference is the book Toolchain chapter; the dist mechanics live in infra/ + the release pipeline.
Sharpe-internal scope means: no LICENSE / no Marketplace publish / no public installer; private bucket via Cloudflare-proxied CloudFront; CI’s ArgonReleaseRole is narrow-scoped (S3 PutObject + CloudFront invalidate only). Okta-gated downloads deferred to v0.3 (separate RFD).
Account note: the distribution lives in AWS account
285688017134, which is thedefaultSSO profile (~/.aws/config) — the shared infra account where the ODE/orca-mvp Pulumi stacks, thes3://sharpe-pulumi-statebackend, and the*.sharpe-dev.comwildcard ACM cert already live. It is not theshared-adminprofile (account548277374575, which is empty). Maintainers authenticate withassume default/AWS_PROFILE=default.
Implementation status (2026-06-02)
- Stage 0 deployed to account
285688017134: S3argon-dist-sharpe+ CloudFrontE16VOSAVQFX5Y8(argon.sharpe-dev.com, proxied) +ArgonReleaseRole(OIDC). Edge verified (HTTP 403 = healthy empty bucket). - Stage 4 merged (PR #6):
release.ymlpublish-dist(OIDC → S3 → CloudFront) + nightly cron, wired via repo secretAWS_ROLE_ARGON_RELEASE+ varARGON_CLOUDFRONT_DIST_ID. Graduated to the §5 toolchain (Stages 1–3 having landed): builds all four binaries, assemblesargon-<v>-<plat>.tar.gzviascripts/assemble-toolchain.sh, and publishes the[artifacts.*]channel-<channel>.tomlviascripts/make-channel-manifest.sh— the schemaoxup installconsumes (round-trip tested inoxup/src/fetch.rs; the format is pinned byscripts/make-channel-manifest.sh). Fixed two latent contract bugs (bare-oxtarball;[platforms.*]vs[artifacts.*]manifest). - Stays in the mgmt account (285). A move to a workload account (prod/623) was investigated and rejected: the workload-account org SCP
p-pif76ezmdeniess3:PutBucketPolicy/PutBucketPublicAccessBlockto interactive SSO admins, so the CloudFront-OAC bucket policy can only be set by an SCP-exempt CI role. For an internal static CDN that’s not worth a full CI-driven deploy apparatus; 285 (where SSO admins can set bucket policies) is the right home for maintainer-operated tooling. Maintainer-localpulumi upruns fromnix develop .#infra. - Adjacent: Argon-aware PR review bots (
claude-review.yml+claude.yml, PR #7) landed alongside this work. - Remaining: Stages 1–3, 5–7 (binary split →
share/std/→oxup→oxfmt→ hostedinstall.sh→ smoke) → tagv0.2.0.
Scope of infra/
This RFD authorizes the new top-level infra/ directory holding the Pulumi project (TypeScript + Bun, matches the ODE pattern at ontology-tooling/infra/) that creates the distribution stack:
argon-dist-sharpeS3 bucket (us-east-2, private, OAC-only read)- CloudFront distribution (PriceClass_100, TLS 1.2+, two cache policies)
- Reuse of the existing
*.sharpe-dev.comwildcard ACM cert (us-east-1) - Cloudflare CNAME
argon.sharpe-dev.com→ CloudFront (proxied / orange cloud) ArgonReleaseRoleIAM role with GitHub OIDC trust forsharpe-dev/argontag pushes
Maintainers run pulumi up locally with the default profile (assume default). CI never touches the infra stack — only the ArgonReleaseRole it outputs.
Scope of oxup/
This RFD also authorizes the new top-level oxup/ directory (Stage 3) — a standalone Rust crate (its own Cargo.toml/Cargo.lock, not a member of compiler/’s workspace) so it stays cheap to build for bootstrap. It is a single binary with argv[0] dispatch:
- Invoked as
ox/oxc/ox-lsp/oxfmt(via symlinks), it resolves the active toolchain (§4) andexecs the real tool from~/.argon/toolchains/<spec>/bin/<tool>. - Invoked as
oxup, it’s the manager CLI (init/install/update/default/list/which/uninstall/self-update).
Decomposition (decided during Stage 2/3): Stage 3 lands in two PRs.
- 3a — network-free foundation: the crate,
argv[0]dispatch, toolchain resolution (§4 precedence), the~/.argonlayout, and the local manager commands (which/list/default/uninstall). Its own CI job incheck.yml. - 3b — the network layer:
install/update/self-update+ auto-fetch-on-miss fromargon.sharpe-dev.com, plus therelease.yml§5 tarball (bin/+share/std+manifest.toml) the fetch consumes. 3b also drops the Stage 2 stdlib embed once the tarball shipsshare/std. Gated on the release pipeline producing real toolchains.
Three-platform build matrix (v0.2)
macos-arm64— all Sharpe dev machines (Apple Silicon)linux-aarch64— ODE sandbox AMIs + arm Linux CI runnerslinux-x86_64— generic Linux + non-arm CI runners
Intel Mac (macos-x86_64) deferred; Windows deferred.
Build order (eight stages, ~8 focused days)
| Stage | Output |
|---|---|
| 0 | infra/ Pulumi project + apply via assume default (account 285688017134) |
| 1 | Compiler binary split (oxc/ox/ox-lsp/oxfmt bin targets in compiler/) |
| 2 | Stdlib migration (include_str! → share/std/) |
| 3 | oxup crate (argv[0] dispatch + channel resolver + auto-fetch) |
| 4 | Release pipeline (GitHub Actions → S3 → CloudFront invalidate) |
| 5 | oxfmt opinionated formatter (parse → CST walk → normalized emit) |
| 6 | Hosted install.sh at argon.sharpe-dev.com/install.sh |
| 7 | Smoke + docs + clean-VM verification |
Out of scope for this RFD
- Okta-gated downloads (Google Workspace SSO) — v0.3 RFD
- Package registry + lockfile — v0.3+ when external deps land
- Apple Developer signing / notarization — internal binaries
- Telemetry payloads — opt-out reserved in
settings.toml; no payload sent
See
- The book Toolchain chapter (
spec/reference/src/toolchain.md) — the user-facing install/channel/version reference /infra/README.md— operator’s guide for runningpulumi up/infra/index.ts— top-level Pulumi wiringontology-tooling/infra/— the ODE pattern this design adapts