Install cin90

cin90 ships as a single static binary for macOS and Linux.

Windows students use cin90 inside WSL2. Install the Linux artifact in the WSL2 distribution and run all cin90 commands from that Linux shell.

Install From A Release

The download page on coderin90.com is the bootstrap for a machine that does not have cin90 yet. The binaries are hosted on S3; each version publishes four artifacts plus their checksums:

  • cin90_<version>_darwin_amd64 · cin90_<version>_darwin_amd64.sha256
  • cin90_<version>_darwin_arm64 · cin90_<version>_darwin_arm64.sha256
  • cin90_<version>_linux_amd64 · cin90_<version>_linux_amd64.sha256
  • cin90_<version>_linux_arm64 · cin90_<version>_linux_arm64.sha256

(<version> is the version string exactly as the manifest gives it, which is unprefixed — e.g. 0.1.0-beta.2, not v0.1.0-beta.2, even though the matching git tag carries the v. The artifact URL is https://cin90-releases.s3.us-east-1.amazonaws.com/<version>/<artifact>, and each artifact's .sha256 and .sig sit beside it at that URL plus the suffix. The bucket has no listing, so the manifest at https://cin90-releases.s3.us-east-1.amazonaws.com/latest.json is where the current version and the four binary URLs come from.)

Releases may be stored gzip-compressed and served with Content-Encoding: gzip, which cuts a 9.4MB download to 3.8MB. No published version is compressed yet, and browsers and cin90 update decode it without being asked in any case. curl does not, unless you pass --compressed, so use it either way:

shell
curl -fsSL --compressed -O \
  https://cin90-releases.s3.<region>.amazonaws.com/<version>/cin90_<version>_<platform>

Against a compressed release, omitting --compressed saves the compressed stream as if it were the binary. That is not a silent failure — the checksum below will not match, and the file will not run — but the checksum is the only thing that tells you. Against an uncompressed one, --compressed is a harmless no-op, which is why it is the safe habit.

A first install is verified by hand, because the embedded signing key can only be checked by a binary that already runs. Download the artifact and its .sha256 sidecar, then compare:

shell
shasum -a 256 -c cin90_<version>_<platform>.sha256
# or on GNU Linux:  sha256sum -c cin90_<version>_<platform>.sha256

The sidecar describes the raw binary — the decompressed bytes — so this is the same check it always was.

An "OK" line means the artifact matches the published checksum. Each release also publishes <artifact>.sig (the detached Ed25519 signature) — the CLI verifies the checksum and that signature before cin90 update replaces the local executable.

Update

Run:

shell
cin90 update

The updater first compares the version the manifest names against the running one and refuses anything that is not newer, so a manifest pointing at an older genuinely-signed build cannot roll you back. Already on the published version, it says so and downloads nothing. A deliberate rollback is cin90 update --force.

Past that guard it downloads the platform artifact named by the manifest, verifies sha256 and the detached signature, writes the replacement beside the current executable, and then atomically renames it into place. A failed download, checksum mismatch, or bad signature leaves the current binary in place.

Install The Push-Time Hook

Run this once per assignment clone:

shell
cin90 install-hook

It sets the repository's core.hooksPath to .githooks and writes a pre-push hook there.

Setting core.hooksPath stops git reading the repository's old hooks directory at all, so hooks that were already installed there — yours, or another tool's — are copied forward as one-line scripts in .githooks that run the original. They keep firing, and a pre-push of your own still decides whether the push goes through. If .githooks already contains a hook cin90 did not write, the install refuses and says so rather than overwriting it.

The directory it copies from is whichever one git is reading, which includes a core.hooksPath you set globally in ~/.gitconfig — the same directory a second run comes back to. Only the hook names git actually runs are copied forward, so a shell library or a spare copy kept alongside them stays where it is.

Run it again after installing another hook. Something like pre-commit install writes into .git/hooks, which git no longer reads, so the new hook would never fire; a second cin90 install-hook re-scans and chains it. Nothing else changes — the same scripts and the same core.hooksPath.

If cin90 cannot capture a push it says so once on stderr and lets the push through: it is a capture trigger, never a gate. The usual cause is cin90 not being on PATH for the program running the hook — a GUI git client or an IDE starts with a minimal environment, so a PATH exported only in ~/.zshrc does not reach it. Install the binary somewhere already on the system PATH, and run cin90 reconstruct to record the session for a push that went uncaptured.

To undo it:

shell
cin90 uninstall-hook

core.hooksPath goes back to whatever it was before — another directory, or no setting at all. The one exception is the mirror image of the clobber above: if core.hooksPath now points somewhere that is not .githooks, something else was installed after cin90, and putting the old value back would silently disable it. cin90 leaves the setting alone, says so, and forgets what it had recorded. Either way the scripts in .githooks are left where they are, inert, because nothing points at them any more.

Read this page in your terminal: install the cin90 CLI and run cin90 docs. The same page is served as raw markdown.