feat(install): the one-command terminal path, and how to read it before you run it (#86) - #88
Merged
Merged
Conversation
…re you run it (#86) Closes #86. keel merged its terminal installer in CodeGateSoftware/keel#479. Until now the only route this page documented was the manual one: download eight wheels from the release page by hand, then `pip install --find-links .`. The script does the whole job in one command, and the page said nothing about it. ### Why this is announceable, when most of the new installer work is not Verified 2026-08-25. The script resolves 200 from `main` and installs from the latest release's wheels — and v0.11.2 carries all five production wheels plus `config.yaml`, so the path works end to end today. `keel update` is registered in that same tag (`keel/cli.py:198,1414`), so the "keeping it current" half is true of the released engine too. Everything else that landed upstream after v0.11.2 is unreleased code on `main` and stays off the site: no `.dmg`, no `.exe`, no signed or notarised build, no `SHA256SUMS`. That is #87, deliberately not this PR. ### The pipe is never offered alone A reader here may hand keel exchange API keys. `curl … | bash` sits beside a download-read-run variant, and the audit comment is localized on its own line so the Arabic build never interleaves RTL prose inside an LTR command line. ### One correction to keel's own words `scripts/install.sh`'s header says it "writes nothing outside the invoking user's home". Line 83 stages downloads in `${TMPDIR:-/tmp}`, so on Linux that is not quite true — removed on exit by the `trap`, but outside `$HOME` while it runs. The page says what is checkable instead: downloads land in a temporary folder deleted on exit, and the *installed deployment* lives only under your home folder. ### Honesty boundaries held The sha256 line is described as an audit trail, **not** a verification — no wheel checksums are published anywhere, so there is nothing to compare against. The script is described as served from the default branch, never as shipped in a release. ### Verification - `npm run check` — 0 errors, 0 warnings (5 pre-existing hints, untouched) - `npm run build` — 56 pages, complete - `#terminal-install` renders in all three locales - `rev` and both `translatedFromRev` at `2026-08-25.1`, so no stale banner - Prohibited-claims sweep from LAUNCH-CHECKLIST §7 — clean Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015cBJ2syTN4VoE73F9sBNGW
This was referenced Aug 25, 2026
…loor is 3.14 (#86) Review found two factual errors in the terminal-installer copy. Both were verified against live sources, not a local clone, and both are corrected in all three locales. ### The config.yaml it lands is not the paper profile The copy said "The config.yaml it lands is the paper profile. Nothing in it can place a live order." Downloading the actual release asset shows otherwise: # keel PRODUCTION configuration -- the `config.yaml` attached to a GitHub Release. # Shipped in `auto_trade.mode: confirm`: keel previews every order and waits for # your explicit approval before placing it. It is ready for live use... auto_trade: mode: confirm `keel/cli.py` at v0.11.2 draws the line plainly: `paper` simulates, `confirm` is live. So it is the live profile behind a per-order gate. Telling a reader it "cannot place a live order" is wrong in the direction that costs money, and it sat directly above the line telling them to add a CDP key. The page now says what it is, and points at the real remedy: from `~/.keel`, `./.venv/bin/keel init-config --force` writes the `mode: paper` template, since without `--live` that is what `template_config_text` returns. **This came from upstream.** `scripts/install.sh` calls it "the paper profile" at the copy step and again in its next-steps output. The site had mirrored it faithfully. Reported for the keel repo separately. ### The Python floor is 3.14, not 3.11 The local keel clone this copy was written against was 12 commits stale. The live script — the one the page's own one-liner fetches — enforces 3.14: say "step 2/7: finding Python >= 3.14" for candidate in python3 python3.14; do Raised in keel `2d3934f`, on `main` but not in the v0.11.2 tag. A reader on 3.12 would have followed this page into a hard failure. The interesting half is kept rather than smoothed over: the script's floor is stricter than the wheels it installs, which still declare `>=3.11`. The manual path above accepts a Python this script turns away, and the page now says so. The hero and from-source requirements are untouched — 3.11 is still right there. ### Two smaller corrections - `keel update` installs only through uv and stops with a plain error when uv is absent, yet the installer works fine without it. A pip-path deployment cannot self-update until uv is added. Said out loud rather than left as a surprise. - uv detection needs `uv --version` to actually succeed — a shim that cannot run is deliberately treated as absent — and the fallback uses the interpreter the script found, not literally `python3`. ### The branch note earns its keep "It works today" was falsified during its own review: `main` moved the floor while the copy sat in a PR. The note now says the script changes when `main` changes, cites that very move as the example, and tells the reader to read the copy they download rather than trust this page to have kept up. It also names what CI does and does not prove — `install-smoke.yml` runs end to end on macOS and Linux, but only on `workflow_dispatch` and PRs touching the script. ### Translations ar and fr carry every caveat intact; the two sentences asserting the old false claim are gone from both. Also dropped a stale "both serve this venv deployment" clause that English no longer has and that the uv caveat now contradicts, and removed a redundant "(checkout)" parenthetical from the Arabic. Arabic bidi marks brought in line with the convention already used elsewhere in the file. ### Verification - `npm run check` — 0 errors, 0 warnings - `npm run build` — 56 pages, complete - All three locales: 13 fields, 8 `does` items, `rev`/`translatedFromRev` all `2026-08-25.1` - `dist` greps: old claim absent in all three; `Python 3.14` and the confirm-mode caveat present in all three Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015cBJ2syTN4VoE73F9sBNGW
…n this today (#86) An adversarial verification pass was run against live sources rather than a local clone. It falsified two claims in the previous commit — including one that commit had itself introduced as a correction — and surfaced a third problem the page had no business staying quiet about. ### "previews every order and waits for your typed approval" was wrong twice **Not typed.** `v0.11.2:keel/commands/confirm.py:196` is `click.confirm("Place this order?", default=False)` — an ordinary y/N prompt defaulting to no. A typed phrase does exist, `DEGRADED_PREVIEW_PHRASE = "place anyway"` at `confirm.py:41`, but only for previews keel considers unreliable. The previous commit had borrowed `keel update`'s gate, which really does demand the word `yes`, and attached it to order placement. **Not every order.** Three money-moving paths hard-code `"autonomous"` with `confirm_fn=None` and place with no prompt even under `mode: confirm`: `executor.py:1556` (`place_bracket`), `:1638` (`scale_out`), `:1719` (`_roll_stop`). Each is a follow-on to a position a human already approved, which is defensible design — but "every" is not what the code does. ### The bullet also traded away its strongest true claim "places nothing until you add venue credentials" is true but is about the fifth gate down. The binding one is `agent.py:1247`: if repo.get_state("kill_switch", default=True): It fails closed. A fresh deployment has no `kill_switch` row, reads `True`, and skips every cycle before evaluating anything — so it trades nothing even with full credentials, until `keel resume`. Seeded rules are `candidate` besides, and only `live` rules trade. The bullet is now split in two: what the config is, and why a fresh install still does nothing. ### The Linux claim was the real find The previous `branchNote` said keel runs the script end to end on macOS and Linux. It is configured to, but has not done so since the floor moved. Run 32714791913, the only one since: smoke (ubuntu-latest) ==> step 2/7: finding Python >= 3.14 smoke (ubuntu-latest) installer: FAIL: no Python >= 3.14 found on PATH macOS found Homebrew's 3.14.6 and installed cleanly; ubuntu-latest died at the version check and took the macOS leg with it via fail-fast. Python 3.14 is new enough that mainstream distributions do not package it, so the one-liner this page publishes fails for most Linux readers today. Saying "you need 3.14" while implying Linux works was accurate word by word and misleading as a whole. The note now says plainly: on Linux, expect to install 3.14 yourself first. ### One pre-existing falsehood, fixed while adjacent `fromSource` promised "any Python 3.11+". That path clones `main`, where `requires-python` is `>=3.14` and `.python-version` is `3.14.4`, so `uv sync` on 3.11 fails. Outside this PR's scope but false in the same way and three lines away; fixed in all three locales rather than left standing. The hero `requirements` and the `unsigned` block keep 3.11 — both describe the published wheels, which still declare `>=3.11`. ### Verification - `npm run check` — 0 errors, 0 warnings - `npm run build` — 56 pages, complete - All three locales: 9 `does` items, 13 fields, revs matched - `dist` greps: y/N prompt, kill-switch and Linux-3.14 warning present in en, ar and fr; the old CI claim absent Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015cBJ2syTN4VoE73F9sBNGW
…and (#86) Polish from the independent review, which returned MERGE. Two of these touch FR-9 directly, so they are applied rather than merged past. ### The warning was in the wrong place It sat four sentences into `branchNote`, a paragraph that opens on branch pinning. A reader scanning for the command copies it long before reaching a "this fails today" buried under provenance prose. The warning now lives in `requires`, beside the other platform requirements. Verified in the rendered HTML: it precedes the first `curl` line in all three locales. `branchNote` goes back to what it is for — the script tracks a moving branch, and the description may not have kept up. ### One clause was not verifiable "most Linux distributions do not package it yet" — Fedora 43+, Arch and openSUSE Tumbleweed do package 3.14. What is true, and what the page now says, is that most distributions still *default* to an older Python. FR-9 asks for claims verifiable the day they ship, and the CI evidence beside it carries the sentence without needing the stronger version. ### The script contradicts the page, so the page says so `install.sh` prints "the paper profile" and "nothing in it can place a live order" for a config that is byte-identical to `config.live.yaml` in `mode: confirm`. A reader who runs the one-liner watches the tool contradict this page with no way to adjudicate, and the error runs in the dangerous direction. The bullet now names it and points at `auto_trade.mode` in the file. Reported upstream separately. ### Two smaller ones - The `keel update` caveat was 40 words, past the ~35 ceiling in CONTRIBUTING and not the parallel enumeration the exception allows. Split in three locales. - The dark `unsigned` block said the five-minute path needs "Python 3.11 or later" while linking `#from-source`, which this branch corrected to 3.14. It renders only when a release carries a platform bundle, so it is latent rather than live — but the rev is already bumped and it would have become a contradiction the day a bundle ships. ### Left alone deliberately The hero `requirements` keeps 3.11: it describes the published wheels, which declare `>=3.11`. So does the reconciliation clause in `requires`, and the "moved from 3.11 to 3.14" in `branchNote` is a historical statement. The review also noted `does[6]` understates the gating — `execute()` routes every intent through `confirm_fn` and only the post-fill bracket bypasses it, and a degraded preview demands a typed phrase. Both errors run in the safe direction, claiming less gating than exists, so the shorter line stands. ### Verification - `npm run check` — 0 errors, 0 warnings - `npm run build` — 56 pages, complete - All three locales: 9 `does` items, 13 fields - Rendered: warning before the curl block in en, ar and fr Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015cBJ2syTN4VoE73F9sBNGW
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Closes #86.
keel merged its terminal installer in CodeGateSoftware/keel#479. Until now the only route this page documented was the manual one: download eight wheels from the release page by hand, then
pip install --find-links .. The script does the whole job in one command, and the page said nothing about it.Why this is announceable, when most of the new installer work is not
I reviewed all seven keel commits that landed after v0.11.2. Almost none of them can go on the site yet, because they have shipped to zero users:
main, resolves 200, installs v0.11.2's wheelsmain, unreleased;signingenvironment does not existmain, unreleasedStatus: proposal, zero code shippedBracketGTC(#502 stage 1)keel/What makes this one different: the script resolves 200 from
mainand installs from the latest release's wheels, and v0.11.2 carries all five production wheels plusconfig.yaml. So the path works end to end today.keel updateis registered in that same tag (keel/cli.py:198,1414), so the "keeping it current" half is true of the released engine too.The pipe is never offered alone
A reader here may hand keel exchange API keys, so
curl … | bashis not presented as the only way in. It sits beside a download-read-run variant, and the audit comment is localized on its own line so the Arabic build never interleaves RTL prose inside an LTR command line.One correction to keel's own words
scripts/install.sh's header claims it "writes nothing outside the invoking user's home". Line 83 stages downloads in${TMPDIR:-/tmp}— removed on exit by thetrap, but outside$HOMEwhile it runs. Rather than repeat the stronger phrasing, the page says what is checkable line by line: downloads land in a temporary folder deleted on exit, and the installed deployment lives only under your home folder.Worth reporting upstream (not fixed here):
docs/desktop-install.mdand the release-notes template both promise a singularSHA256SUMS.txt, butrelease.ymlemits one file per leg —SHA256SUMS-macOS-arm64.txt,SHA256SUMS-macOS-x86_64.txt,SHA256SUMS-Windows-x86_64.txt.Honesty boundaries held (FR-9)
.dmg,.exe, signed/notarised build, orSHA256SUMSis mentioned. The existingunsignedblock and thebrowserTitle/browserBodyv0.11.0 claim are byte-identical to before.Structure
Two files.
src/pages/{en,ar,fr}/install.astroare untouched — they are 4-line wrappers with no copy, per the design contract indocs/DEPLOYMENT.md.src/i18n/pages/install.ts— newTerminalInstallCopyinterface,terminalfield onInstallContent, copy in all three locales.src/components/pages/InstallPage.astro— command strings in frontmatter, new<section id="terminal-install">placed ahead of the wheels-by-hand ceremony.#from-sourcestays last.FR-8: all three
rev→2026-08-25.1, bothtranslatedFromRev→2026-08-25.1, so no stale-translation banner renders.Verification
npm run check— 0 errors, 0 warnings (5 pre-existing hints in files this PR does not touch)npm run build— 56 pages built, complete#terminal-installrenders indist/{en,ar,fr}/install/index.htmlLAUNCH-CHECKLIST§7 — cleanWHEEL_PREFIXESatscripts/install.sh:39./.venv/bin/keel updateform matches the installer's own "Next steps" output (install.sh:227-235)Reviewer attention
#from-source. Is one command ahead of the wheels ceremony the right order, or should the download grid keep the first word?main, and it works today". Honest, but it does invite the question of what happens whenmainmoves. Worth a stronger caveat?🤖 Generated with Claude Code
https://claude.ai/code/session_015cBJ2syTN4VoE73F9sBNGW