The install pipeline for the Corvid programming language. End users install Corvid in one line; this repo is the development workspace where the install machinery was authored.
Canonical locations. The files in this repo are mirrored into the Corvid-lang repo, and that's where users actually fetch them from at runtime. Do not point users at this repo's URLs — point them at Corvid-lang's:
install/install.shandinstall/install.ps1→Micrurus-Ai/Corvid-lang/install/release.ymlandpublish-managers.yml→Micrurus-Ai/Corvid-lang/.github/workflows/worker.jsandwrangler.toml→Micrurus-Ai/Corvid-lang/web/- The Homebrew tap →
Micrurus-Ai/homebrew-corvid- The Scoop bucket →
Micrurus-Ai/scoop-corvid
- Install Corvid (end users)
- What gets installed
- Architecture
- Pipeline components
- Supported targets
- Configuration reference
- Cutting a release
- Operations runbook
- Local development
- Uninstall
- Design decisions
- License
Open follow-up tasks (push this repo, narrow PAT scope, deploy Cloudflare, etc.) live in FOLLOWUPS.md.
Four supported paths. Pick the one that matches how you already install developer tools.
macOS / Linux:
curl -fsSL https://raw.githubusercontent.com/Micrurus-Ai/Corvid-lang/main/install/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/Micrurus-Ai/Corvid-lang/main/install/install.ps1 | iexDetects your OS and CPU architecture, downloads the matching prebuilt archive from the latest GitHub Release, drops corvid on your PATH, and runs corvid doctor. Falls back to a cargo install from source if no prebuilt is available for your platform.
brew install Micrurus-Ai/corvid/corvidThis expands to brew tap Micrurus-Ai/corvid && brew install corvid. The formula points at the same prebuilt archives, with sha256s verified by Homebrew.
scoop bucket add corvid https://github.com/Micrurus-Ai/scoop-corvid
scoop install corvidThe bucket manifest declares a checkver/autoupdate block, so Scoop's central bot keeps it current with Corvid releases on its own (~24h cadence after a tag).
git clone https://github.com/Micrurus-Ai/Corvid-lang
cd Corvid-lang
cargo install --path crates/corvid-cli --lockedSlowest path (5–15 min on a cold build), but works on any platform with a Rust toolchain. The bootstrap scripts fall back to this automatically when prebuilt binaries aren't available.
After any of the four, in a fresh shell:
corvid --help
corvid doctor
corvid tour --list
~/.corvid/ (Linux/macOS)
%USERPROFILE%\.corvid\ (Windows)
├── bin/
│ └── corvid(.exe) # the CLI; added to your PATH
├── std/ # Corvid standard library
│ ├── ai.cor
│ ├── auth.cor
│ ├── effects.cor
│ └── ...
├── LICENSE-MIT
├── LICENSE-APACHE
├── README.md
└── src/ # only present when source-built
Two environment changes:
PATHgains$CORVID_HOME/bin.CORVID_HOMEpoints at the install root.corvid new <project>reads this to vendor the stdlib into fresh projects soimport "./std/foo"works without further setup.
Homebrew installs to its own prefix ($(brew --prefix corvid)), Scoop installs to its bucket directory. The directory layout (bin/ next to std/) is identical so the find_std_source resolver in corvid new finds the stdlib in all three cases.
END USER
│
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
curl … install.sh brew install … scoop install corvid
│ │ │
└────────┬───────────┴────────────────────┘
│
▼ (downloads matching archive)
┌──────────────────────────────────────────────┐
│ github.com/Micrurus-Ai/Corvid-lang │
│ /releases/v<X.Y.Z>/corvid-<target>.* │
└──────────────────────────────────────────────┘
▲
│ uploaded by
┌──────────────────────────────────────────────┐
│ release.yml (triggered by `git push v*.*.*`) │
│ builds 4 prebuilt archives in parallel │
└──────────────────────────────────────────────┘
│
▼ (on success, triggers)
┌──────────────────────────────────────────────┐
│ publish-managers.yml │
│ bumps homebrew-corvid/Formula/corvid.rb │
└──────────────────────────────────────────────┘
Scoop's central bot polls Corvid-lang's releases page
independently and bumps scoop-corvid every ~24h.
Two trigger events drive the whole pipeline:
- Push a
v*.*.*tag →release.ymlbuilds → archives uploaded →publish-managers.ymlbumps Homebrew. Whole flow: ~15 min start to finish. - Push to
install/**orweb/**→test-installers.ymllints + smoke-tests the bootstrap scripts. Catches regressions before users see them.
Nothing else in this pipeline needs human attention between releases.
POSIX sh script (works under bash, zsh, dash, ash). Invoked via curl … | sh. Cross-platform between macOS and Linux, x86_64 and aarch64. ~150 lines.
Behavior, in order:
- Detect OS (
linux*/darwin*) and arch (x86_64/aarch64). - Build the prebuilt asset URL for the resolved target triple.
- Try to download the archive with
curl(orwgetfallback) into a temp dir. - Fast path: extract into
$CORVID_HOME, installbin/corvidandstd/. - Fallback: if the download 404'd, install
rustupif needed,git clone --depth 1Corvid-lang, runcargo install --path crates/corvid-cli --locked --root $CORVID_HOME. - Append a
# corvidblock to~/.bashrc/~/.zshrc/~/.profileexportingCORVID_HOMEand updatingPATH. - Run
corvid doctorfor a final health check.
Configurable via env vars (see Configuration reference).
Same logic as the Unix script, in PowerShell 5.1+. Invoked via irm … | iex. ~150 lines.
Two Windows-specific quirks worth knowing:
- The fallback path uses
winget install Rustlang.Rustupfirst, then falls back to downloadingrustup-init.exefromwin.rustup.rs/x86_64. PATHis updated via[Environment]::SetEnvironmentVariable(...)at User scope (not Machine — no admin needed). Users must open a new terminal to see it.
Triggers on push: tags: ["v*.*.*"]. Four parallel jobs:
| OS runner | Target triple | Archive |
|---|---|---|
ubuntu-latest |
x86_64-unknown-linux-gnu |
.tar.gz |
macos-latest |
x86_64-apple-darwin |
.tar.gz |
macos-latest |
aarch64-apple-darwin |
.tar.gz |
windows-latest |
x86_64-pc-windows-msvc |
.zip |
Each job:
- Checkout, install Rust toolchain with the target added.
cargo build --release --locked --target $TARGET -p corvid-cli(this is the long step — 5–10 min on cold runners).- Stage
bin/corvid(.exe)+std/+ licenses intodist/corvid-<target>/. - Archive (tar.gz on Unix, zip on Windows).
- Upload to the release via
softprops/action-gh-release@v2.
The --locked flag requires Cargo.lock to be present and unchanged — it's committed to the repo for exactly this reason.
Triggers on workflow_run: workflows: ["release"], types: [completed] and runs only when the upstream run succeeded with a tag head ref. Also exposes workflow_dispatch with a tag input for manual re-runs.
Steps:
- Resolve the tag and version (
v0.1.0→0.1.0). - Download each macOS/Linux release archive, compute sha256s.
- Checkout
Micrurus-Ai/homebrew-corvidusing theMANAGERS_TOKENPAT. - Rewrite
Formula/corvid.rbwith the new version + sha256s (a small Python regex pass). - Commit as
corvid <version>and push.
If the formula is already at that version (e.g., re-running for the same tag), the script's git diff --cached --quiet guard exits 0 cleanly — idempotent.
Scoop is intentionally not handled here. The Scoop manifest declares checkver/autoupdate, so Scoop's central bot tracks Corvid releases on its own. Nothing for us to maintain.
Triggers on push/pull_request to install/**, web/**, or this file itself. Three job tiers:
lint(~30s):shellcheckandsh -noninstall.sh,node --checkonworker.js. Runs on every PR.pwsh-lint(~60s):Invoke-ScriptAnalyzeroninstall.ps1with-ExcludeRule PSAvoidUsingWriteHost(Write-Host is the right call for an interactive bootstrap). Runs on every PR.smoke-linux(~10 min): runsinstall.shend-to-end against the current checkout withCORVID_VERSION=nonexistent-test-tagto force the source-build fallback path. Asserts thatcorvidlands onPATHand thatcorvid new testprojproduces a project withcorvid.toml,src/main.cor, and a vendoredstd/. Slow but gates a real regression class.smoke-matrix(macOS + Windows): same end-to-end test, butworkflow_dispatchonly — too slow to run on every PR.
A Cloudflare Worker that turns one origin (e.g. corvid.sh) into three responses based on User-Agent:
| Caller | Response |
|---|---|
curl / wget |
install/install.sh content |
| PowerShell | install/install.ps1 content |
| Web browser | A branded landing page (inlined HTML) with copy-paste commands auto-highlighted for the visitor's OS |
Scripts are proxied straight from raw.githubusercontent.com/Micrurus-Ai/Corvid-lang/main/install/... and cached at the edge for 5 min. Editing the install scripts in main updates the served content within 5 min, no Worker redeploy required.
Free Cloudflare tier covers ~100k installs/day. Deploy: wrangler login && wrangler deploy from web/. See Corvid-lang/web/README.md for full deploy steps and DNS setup.
A standard Homebrew tap (homebrew-<name> repo naming convention). One file: Formula/corvid.rb, a Ruby class that declares prebuilt URLs and sha256s for macOS Apple Silicon, macOS Intel, and Linux x86_64. The def install block places bin/corvid and prefix/std in the right spots so find_std_source resolves the stdlib via the binary's neighborhood.
Auto-bumped on every release by publish-managers.yml.
A Scoop bucket. One file: bucket/corvid.json, declaring the Windows zip URL, sha256, extract_dir, and bin path. Sets env_set: { CORVID_HOME: $dir } so corvid new finds the stdlib next to the binary.
Includes checkver/autoupdate, so Scoop's central bot bumps the manifest automatically when new Corvid releases ship.
A change in crates/corvid-driver/src/scaffold.rs that hooks into corvid new <project>: after creating the standard scaffold (corvid.toml, src/main.cor, tools.py, .gitignore), the function calls vendor_std(&project_root) which:
- Looks up the system
std/directory using:$CORVID_HOME/stdifCORVID_HOMEis set, else<exe-dir>/../std(the layout the installer produces).
- If found, recursively copies it into
<project>/std/. - If not found, silently no-ops.
This closes the gap between "install Corvid" and "write working code." Before this change, import "./std/effects" in a fresh project failed because the resolver is purely path-relative — it has no system search path. With it, every install pathway (curl bootstrap, brew, scoop) produces a corvid new flow that just works.
Fast path (prebuilt downloads):
| OS | Architecture | Target triple | Archive |
|---|---|---|---|
| Linux | x86_64 | x86_64-unknown-linux-gnu |
.tar.gz |
| macOS | Intel | x86_64-apple-darwin |
.tar.gz |
| macOS | Apple Silicon | aarch64-apple-darwin |
.tar.gz |
| Windows | x86_64 | x86_64-pc-windows-msvc |
.zip |
Other targets (e.g. Linux aarch64, FreeBSD, Windows ARM64) automatically use the source-build fallback. To add a new target to the fast path, extend the matrix in release.yml and the OS/arch detection in install.sh / install.ps1.
| Variable | Default | Purpose |
|---|---|---|
CORVID_REPO |
Micrurus-Ai/Corvid-lang |
Source repo to install from. Override to install from a fork. |
CORVID_VERSION |
latest |
Release tag, e.g. v0.1.0. |
CORVID_HOME |
$HOME/.corvid (or %USERPROFILE%\.corvid on Windows) |
Install root. |
Pin a specific version:
CORVID_VERSION=v0.1.0 curl -fsSL https://raw.githubusercontent.com/Micrurus-Ai/Corvid-lang/main/install/install.sh | shInstall from a fork:
CORVID_REPO=myuser/Corvid-lang curl -fsSL https://raw.githubusercontent.com/myuser/Corvid-lang/main/install/install.sh | sh| Secret | Used by | Purpose |
|---|---|---|
MANAGERS_TOKEN |
publish-managers.yml |
Fine-grained PAT with Contents: Read and write scoped to Micrurus-Ai/homebrew-corvid. Lets the workflow push the bumped formula. |
GITHUB_TOKEN |
release.yml |
Provided by GitHub Actions. Used by softprops/action-gh-release@v2 to create the release object and upload assets. No setup needed. |
cd Corvid-lang
git checkout main && git pull
git tag v0.1.1
git push origin v0.1.1That triggers everything. ~15 minutes later:
- ✓
release.ymlhas built and uploaded 4 archives tohttps://github.com/Micrurus-Ai/Corvid-lang/releases/tag/v0.1.1. - ✓
publish-managers.ymlhas pushed acorvid 0.1.1commit tohomebrew-corvid/Formula/corvid.rb. - ⏳ Scoop's central bot will pick up the new version on its next daily run (within ~24h).
The bootstrap one-liners point at releases/latest/download/... and update instantly the moment release.yml finishes.
# Are all 4 archives published?
for t in aarch64-apple-darwin x86_64-apple-darwin x86_64-unknown-linux-gnu x86_64-pc-windows-msvc; do
ext=tar.gz; [ "$t" = "x86_64-pc-windows-msvc" ] && ext=zip
printf '%-30s %s\n' "$t" "$(curl -sIo /dev/null -w '%{http_code}' "https://github.com/Micrurus-Ai/Corvid-lang/releases/download/v0.1.1/corvid-${t}.${ext}")"
done
# Did the formula bump?
curl -fsSL https://raw.githubusercontent.com/Micrurus-Ai/homebrew-corvid/main/Formula/corvid.rb | grep '^ version'
# Does the install actually work?
CORVID_VERSION=v0.1.1 sh install/install.sh
~/.corvid/bin/corvid --versionThe PAT used by publish-managers.yml expires (currently set to ~1 year). When it does, the post-release Homebrew bump silently fails until rotated.
- https://github.com/settings/personal-access-tokens → click
corvid-managers-bot→ Regenerate token. - Verify Repository access still includes
Micrurus-Ai/homebrew-corvidand Repository permissions still grantContents: Read and write. - Copy the new
github_pat_…value. - https://github.com/Micrurus-Ai/Corvid-lang/settings/secrets/actions → click
MANAGERS_TOKEN→ Update secret → paste → save. - Test: trigger
publish-managers.ymlviaworkflow_dispatchwith tagv<latest>. Should succeed in ~30s (no-op push) or commit a fresh bump.
The build step (cargo build --release --locked --target X -p corvid-cli) is the most common failure point. By order of likelihood:
Cargo.lockout of sync withCargo.toml. Runcargo buildlocally, commit the updatedCargo.lock, push, retag (or push av0.1.x+1).- One platform breaks specifically. Usually a target-specific dep (e.g.
rusqliteneedslibsqlite3-devon some Linux distros, or a Windows-specific feature flag is missing). Check the failed job's log on the Actions tab. - Cross-compile linker missing. Only relevant if you add aarch64-linux to the matrix; needs
gcc-aarch64-linux-gnuinstalled on the ubuntu runner.
If release.yml succeeded but the GitHub Release object is missing assets, look at the Upload to release step — usually a transient network blip; re-run failed jobs.
If publish-managers.yml fails and you need the formula bumped before the next release, do it locally:
git clone https://github.com/Micrurus-Ai/homebrew-corvid && cd homebrew-corvid
VERSION=0.1.1
for t in aarch64-apple-darwin x86_64-apple-darwin x86_64-unknown-linux-gnu; do
url="https://github.com/Micrurus-Ai/Corvid-lang/releases/download/v${VERSION}/corvid-${t}.tar.gz"
sum=$(curl -fsSL "$url" | sha256sum | awk '{print $1}')
echo "$t $sum"
doneEdit Formula/corvid.rb directly:
- Update
version "X.Y.Z". - Replace each of the three placeholder/old
sha256 "..."values with the new ones (one peron_arm/on_intelblock).
Commit and push:
git commit -am "corvid $VERSION"
git push origin mainScoop's central bot usually handles this on its own within 24h. If you need it sooner:
git clone https://github.com/Micrurus-Ai/scoop-corvid && cd scoop-corvid
VERSION=0.1.1
url="https://github.com/Micrurus-Ai/Corvid-lang/releases/download/v${VERSION}/corvid-x86_64-pc-windows-msvc.zip"
sum=$(curl -fsSL "$url" | sha256sum | awk '{print $1}')
echo "$sum"Edit bucket/corvid.json to update the version, architecture.64bit.url, and architecture.64bit.hash fields. Commit and push.
The Worker only needs redeploy when its logic changes — not when the install scripts change (those are proxied at request time). To redeploy:
cd Corvid-lang/web
wrangler login # one-time
wrangler deployTo verify routing works after a custom-domain change:
curl -I https://corvid.sh # → 200 text/html
curl -I -A 'curl/8.0' https://corvid.sh # → 200 text/x-shellscript
curl -I -A 'PowerShell/7.4' https://corvid.sh # → 200 text/plain (install.ps1)https://github.com/Micrurus-Ai/Corvid-lang/actions/workflows/publish-managers.yml
→ Run workflow → Tag: v0.1.1 → Run workflow
Idempotent: if the formula is already at that version, the script exits 0 cleanly without a no-op commit.
In a clean directory, point at this checkout's script and force the cargo fallback so you don't depend on a real release:
CORVID_VERSION=nonexistent-test-tag \
CORVID_REPO=Micrurus-Ai/Corvid-lang \
CORVID_HOME=/tmp/corvid-test \
sh install/install.sh
/tmp/corvid-test/bin/corvid --helpFor a faster iteration loop, run inside Docker:
docker run --rm -it -v "$PWD/install:/install" ubuntu:24.04 bash
# inside:
apt-get update && apt-get install -y curl ca-certificates
CORVID_HOME=/root/.corvid CORVID_VERSION=v0.1.0 sh /install/install.shIn a fresh PowerShell session:
$env:CORVID_HOME = "$env:TEMP\corvid-test"
$env:CORVID_VERSION = "v0.1.0"
.\install\install.ps1
& $env:CORVID_HOME\bin\corvid.exe --helpTo lint locally:
Invoke-ScriptAnalyzer -Path install\install.ps1 -Severity Error,Warning -ExcludeRule PSAvoidUsingWriteHostcd web
wrangler dev
# in another terminal:
curl -fsSL http://localhost:8787 # → HTML landing page
curl -fsSL -A 'curl/8.0' http://localhost:8787 # → install.sh content
curl -fsSL -A 'PowerShell/7' http://localhost:8787 # → install.ps1 contentPush your changes to a branch, then push a pre-release tag:
git checkout -b ci-test
git push -u origin ci-test
git tag v0.0.99-rc1
git push origin v0.0.99-rc1Watch the Actions tab. When you're done, delete the tag and the Release object:
git push --delete origin v0.0.99-rc1
gh release delete v0.0.99-rc1 -y # if gh CLI is installedmacOS / Linux:
rm -rf ~/.corvid
# Then remove the `# corvid` block from any of:
# ~/.bashrc ~/.zshrc ~/.profileWindows:
Remove-Item -Recurse -Force "$env:USERPROFILE\.corvid"
[Environment]::SetEnvironmentVariable('CORVID_HOME', $null, 'User')
# Also strip the .corvid\bin entry from your user PATH:
# sysdm.cpl → Advanced → Environment Variables → Path (User) → EditHomebrew:
brew uninstall corvid
brew untap Micrurus-Ai/corvidScoop:
scoop uninstall corvid
scoop bucket rm corvidIndustry norm. rustup, bun, deno, pnpm, nvm, ohmyzsh, Homebrew itself all ship this way. Developers recognize the pattern, every shell on every platform supports it, no package manager is required, and the script can adapt to the user's environment in ways a static binary download can't. Yes, it requires trusting the URL — but that's true of every install method, and a curl-pipe is more auditable than an opaque MSI/PKG.
cargo install --path crates/corvid-cli --locked works, but a cold build takes 5–15 minutes. For a brand-new language, that latency is fatal — most evaluators bounce in <60 seconds. Prebuilt archives drop that to ~10 seconds. The cargo path stays as a fallback for unusual platforms and as a proof that the source builds.
Pages can do path-based redirects but not User-Agent-based content negotiation. We need the same URL (corvid.sh) to return three different bodies (sh, ps1, HTML) depending on who's asking. A 302 redirect doesn't work because curl … | sh doesn't follow redirects without -L, and asking every user to remember -L defeats the simplicity. The Worker is ~50 lines of JS, free up to 100k requests/day, and carries automatic edge caching.
The Corvid module resolver (crates/corvid-resolve/src/modules.rs) is purely relative to the importing .cor file. There is no search-path mechanism, no CORVID_STD env var, no embedded stdlib. So import "./std/foo" literally requires a std/ directory in the user's project. Without auto-vendoring, every new user discovers this the hard way after their first import statement breaks the build. Hooking into corvid new to copy $CORVID_HOME/std into each new project closes the gap between "install Corvid" and "write working code."
corvid-cli is a binary crate. The standard Rust convention for binaries is to commit the lockfile so that release builds are byte-reproducible across contributors and CI. The repo originally had Cargo.lock in .gitignore (the cargo new --lib default, correct for libraries) — that mismatch caused the first release.yml run to fail on every platform with cargo build --locked because the lockfile wasn't there. Fixing the gitignore + committing the lockfile resolved it.
The corvid.sh short URL is polish, not infrastructure. The bootstrap scripts live at stable raw.githubusercontent.com/Micrurus-Ai/Corvid-lang/main/install/... URLs that work whether or not Cloudflare is involved. If the Worker ever goes down, the long URLs in the README still install Corvid identically. The Worker is purely a UX optimization.
Different developers have different muscle memory:
- Rustaceans expect
cargo install. We support it, with the bootstrap as fallback. - macOS devs expect
brew install. The tap delivers it. - Windows developers split between
winget,scoop, and just downloading. Scoop is the closest analog to brew; it works. - Everyone else lands on the curl/irm one-liner.
Maintaining all four is cheap because the heavy lifting (build matrix, sha256 distribution) happens once; each install path is a thin manifest pointing at the same artifacts.
Dual-licensed under MIT or Apache-2.0, at your option, matching upstream Corvid-lang.